Merge pull request #6521 from adityamandaleeka/remove_internal_free
[platform/upstream/coreclr.git] / src / pal / src / debug / debug.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     debug.c
12
13 Abstract:
14
15     Implementation of Win32 debugging API functions.
16
17 Revision History:
18
19
20
21 --*/
22
23 #ifndef BIT64
24 #undef _LARGEFILE64_SOURCE
25 #undef _FILE_OFFSET_BITS
26 #endif
27
28 #include "pal/dbgmsg.h"
29 SET_DEFAULT_DEBUG_CHANNEL(DEBUG); // some headers have code with asserts, so do this first
30
31 #include "pal/thread.hpp"
32 #include "pal/procobj.hpp"
33 #include "pal/file.hpp"
34
35 #include "pal/palinternal.h"
36 #include "pal/process.h"
37 #include "pal/context.h"
38 #include "pal/debug.h"
39 #include "pal/environ.h"
40 #include "pal/malloc.hpp"
41 #include "pal/module.h"
42 #include "pal/stackstring.hpp"
43 #include "pal/virtual.h"
44
45 #include <signal.h>
46 #include <unistd.h>
47 #if HAVE_PROCFS_CTL
48 #include <unistd.h>
49 #elif HAVE_TTRACE // HAVE_PROCFS_CTL
50 #include <sys/ttrace.h>
51 #else // HAVE_TTRACE
52 #include <sys/ptrace.h>
53 #endif  // HAVE_PROCFS_CTL
54 #if HAVE_VM_READ
55 #include <mach/mach.h>
56 #endif  // HAVE_VM_READ
57 #include <errno.h>
58 #include <sys/types.h>
59 #include <sys/wait.h>
60
61 #if HAVE_PROCFS_H
62 #include <procfs.h>
63 #endif // HAVE_PROCFS_H
64
65 #if HAVE_MACH_EXCEPTIONS
66 #include "../exception/machexception.h"
67 #endif // HAVE_MACH_EXCEPTIONS
68
69 using namespace CorUnix;
70
71 extern "C" void DBG_DebugBreak_End();
72
73 #if HAVE_PROCFS_CTL
74 #define CTL_ATTACH      "attach"
75 #define CTL_DETACH      "detach"
76 #define CTL_WAIT        "wait"
77 #endif   // HAVE_PROCFS_CTL
78
79 /* ------------------- Constant definitions ----------------------------------*/
80
81 #if !HAVE_VM_READ && !HAVE_PROCFS_CTL
82 const BOOL DBG_ATTACH       = TRUE;
83 const BOOL DBG_DETACH       = FALSE;
84 #endif
85 static const char PAL_OUTPUTDEBUGSTRING[]    = "PAL_OUTPUTDEBUGSTRING";
86
87 #ifdef _DEBUG
88 #define ENABLE_RUN_ON_DEBUG_BREAK 1
89 #endif // _DEBUG
90
91 #ifdef ENABLE_RUN_ON_DEBUG_BREAK
92 static const char PAL_RUN_ON_DEBUG_BREAK[]   = "PAL_RUN_ON_DEBUG_BREAK";
93 #endif // ENABLE_RUN_ON_DEBUG_BREAK
94
95 /* ------------------- Static function prototypes ----------------------------*/
96
97 #if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
98 static int
99 DBGWriteProcMem_Int(DWORD processId, int *addr, int data);
100 static int
101 DBGWriteProcMem_IntWithMask(DWORD processId, int *addr, int data,
102                             unsigned int mask);
103 #endif  // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
104
105 #if !HAVE_VM_READ && !HAVE_PROCFS_CTL
106
107 static BOOL 
108 DBGAttachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
109
110 static BOOL
111 DBGDetachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
112
113 static int
114 DBGSetProcessAttached(CPalThread *pThread, HANDLE hProcess, BOOL bAttach);
115
116 #endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
117
118 extern "C" {
119
120 /*++
121 Function:
122   FlushInstructionCache
123
124 The FlushInstructionCache function flushes the instruction cache for
125 the specified process.
126
127 Remarks
128
129 This is a no-op for x86 architectures where the instruction and data
130 caches are coherent in hardware. For non-X86 architectures, this call
131 usually maps to a kernel API to flush the D-caches on all processors.
132
133 --*/
134 BOOL
135 PALAPI
136 FlushInstructionCache(
137         IN HANDLE hProcess,
138         IN LPCVOID lpBaseAddress,
139         IN SIZE_T dwSize)
140 {
141     BOOL Ret;
142
143     PERF_ENTRY(FlushInstructionCache);
144     ENTRY("FlushInstructionCache (hProcess=%p, lpBaseAddress=%p dwSize=%d)\
145           \n", hProcess, lpBaseAddress, dwSize);
146
147     if (lpBaseAddress != NULL)
148     {
149         Ret = DBG_FlushInstructionCache(lpBaseAddress, dwSize);
150     }
151     else
152     {
153         Ret = TRUE;
154     }
155
156     LOGEXIT("FlushInstructionCache returns BOOL %d\n", Ret);
157     PERF_EXIT(FlushInstructionCache);
158     return Ret;
159 }
160
161
162 /*++
163 Function:
164   OutputDebugStringA
165
166 See MSDN doc.
167 --*/
168 VOID
169 PALAPI
170 OutputDebugStringA(
171         IN LPCSTR lpOutputString)
172 {
173     PERF_ENTRY(OutputDebugStringA);
174     ENTRY("OutputDebugStringA (lpOutputString=%p (%s))\n",
175           lpOutputString ? lpOutputString : "NULL",
176           lpOutputString ? lpOutputString : "NULL");
177
178     // As we don't support debug events, we are going to output the debug string
179     // to stderr instead of generating OUT_DEBUG_STRING_EVENT. It's safe to tell
180     // EnvironGetenv not to make a copy of the value here since we only want to
181     // check whether it exists, not actually use it.
182     if ((lpOutputString != NULL) &&
183         (NULL != EnvironGetenv(PAL_OUTPUTDEBUGSTRING, /* copyValue */ FALSE)))
184     {
185         fprintf(stderr, "%s", lpOutputString);
186     }
187
188     LOGEXIT("OutputDebugStringA returns\n");
189     PERF_EXIT(OutputDebugStringA);
190 }
191
192 /*++
193 Function:
194   OutputDebugStringW
195
196 See MSDN doc.
197 --*/
198 VOID
199 PALAPI
200 OutputDebugStringW(
201         IN LPCWSTR lpOutputString)
202 {
203     CHAR *lpOutputStringA;
204     int strLen;
205
206     PERF_ENTRY(OutputDebugStringW);
207     ENTRY("OutputDebugStringW (lpOutputString=%p (%S))\n",
208           lpOutputString ? lpOutputString: W16_NULLSTRING,
209           lpOutputString ? lpOutputString: W16_NULLSTRING);
210     
211     if (lpOutputString == NULL) 
212     {
213         OutputDebugStringA("");
214         goto EXIT;
215     }
216
217     if ((strLen = WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, NULL, 0, 
218                                       NULL, NULL)) 
219         == 0)
220     {
221         ASSERT("failed to get wide chars length\n");
222         SetLastError(ERROR_INTERNAL_ERROR);
223         goto EXIT;
224     }
225
226     /* strLen includes the null terminator */
227     if ((lpOutputStringA = (LPSTR) InternalMalloc((strLen * sizeof(CHAR)))) == NULL)
228     {
229         ERROR("Insufficient memory available !\n");
230         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
231         goto EXIT;
232     }
233
234     if(! WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, 
235                              lpOutputStringA, strLen, NULL, NULL)) 
236     {
237         ASSERT("failed to convert wide chars to multibytes\n");
238         SetLastError(ERROR_INTERNAL_ERROR);
239         free(lpOutputStringA);
240         goto EXIT;
241     }
242     
243     OutputDebugStringA(lpOutputStringA);
244     free(lpOutputStringA);
245
246 EXIT:
247     LOGEXIT("OutputDebugStringW returns\n");
248     PERF_EXIT(OutputDebugStringW);
249 }
250
251 #ifdef ENABLE_RUN_ON_DEBUG_BREAK
252 /*
253    When DebugBreak() is called, if PAL_RUN_ON_DEBUG_BREAK is set,
254    DebugBreak() will execute whatever command is in there.
255
256    PAL_RUN_ON_DEBUG_BREAK must be no longer than 255 characters.
257
258    This command string inherits the current process's environment,
259    with two additions:
260       PAL_EXE_PID  - the process ID of the current process
261       PAL_EXE_NAME - the name of the executable of the current process
262
263    When DebugBreak() runs this string, it periodically polls the child process
264    and blocks until it finishes. If you use this mechanism to start a
265    debugger, you can break this poll loop by setting the "spin" variable in
266    run_debug_command()'s frame to 0, and then the parent process can
267    continue.
268
269    suggested values for PAL_RUN_ON_DEBUG_BREAK:
270      to halt the process for later inspection:
271        'echo stopping $PAL_EXE_PID; kill -STOP $PAL_EXE_PID; sleep 10'
272
273      to print out the stack trace:
274        'pstack $PAL_EXE_PID'
275
276      to invoke the gdb debugger on the process:
277        'set -x; gdb $PAL_EXE_NAME $PAL_EXE_PID'
278
279      to invoke the ddd debugger on the process (requires X11):
280        'set -x; ddd $PAL_EXE_NAME $PAL_EXE_PID'
281 */
282
283 static
284 int
285 run_debug_command (const char *command)
286 {
287     int pid;
288     Volatile<int> spin = 1;
289
290     if (!command) {
291         return 1;
292     }
293
294     printf("Spawning command: %s\n", command);
295     
296     pid = fork();
297     if (pid == -1) {
298         return -1;
299     }
300     if (pid == 0) {
301         const char *argv[4] = { "sh", "-c", command, 0 };
302         execv("/bin/sh", (char **)argv);
303         exit(127);
304     }
305
306     /* We continue either when the spawned process has stopped, or when
307        an attached debugger sets spin to 0 */
308     while (spin != 0) {
309         int status = 0;
310         int ret = waitpid(pid, &status, WNOHANG);
311         if (ret == 0) {
312             int i;
313             /* I tried to use sleep for this, and that works everywhere except
314                FreeBSD. The problem on FreeBSD is that if the process gets a
315                signal while blocked in sleep(), gdb is confused by the stack */
316             for (i = 0; i < 1000000; i++)
317                 ;
318         }
319         else if (ret == -1) {
320             if (errno != EINTR) {
321                 return -1;
322             }
323         }
324         else if (WIFEXITED(status)) {
325             return WEXITSTATUS(status);
326         }
327         else {
328             fprintf (stderr, "unexpected return from waitpid\n");
329             return -1;
330         }
331     };
332     return 0;
333 }
334 #endif // ENABLE_RUN_ON_DEBUG_BREAK
335
336 #define PID_TEXT "PAL_EXE_PID="
337 #define EXE_TEXT "PAL_EXE_NAME="
338
339 static
340 int
341 DebugBreakCommand()
342 {
343 #ifdef ENABLE_RUN_ON_DEBUG_BREAK
344     extern MODSTRUCT exe_module;
345
346     char *command_string = EnvironGetenv(PAL_RUN_ON_DEBUG_BREAK);
347     if (command_string)
348     {
349         char pid_buf[sizeof (PID_TEXT) + 32];
350         PathCharString exe_bufString;
351         int libNameLength = 10;
352
353         if (exe_module.lib_name != NULL)
354         {
355             libNameLength = PAL_wcslen(exe_module.lib_name);
356         }
357         
358         SIZE_T dwexe_buf = strlen(EXE_TEXT) + libNameLength + 1;
359         CHAR * exe_buf = exe_bufString.OpenStringBuffer(dwexe_buf);
360         
361         if (NULL == exe_buf)
362         {
363             goto FAILED;
364         }
365
366         if (snprintf (pid_buf, sizeof (pid_buf), PID_TEXT "%d", getpid()) <= 0)
367         {
368             goto FAILED;
369         }
370
371         if (snprintf (exe_buf, sizeof (CHAR) * (dwexe_buf + 1), EXE_TEXT "%ls", (wchar_t *)exe_module.lib_name) <= 0)
372         {
373             goto FAILED;
374         }
375
376         exe_bufString.CloseBuffer(dwexe_buf);
377         /* strictly speaking, we might want to only set these environment
378            variables in the child process, but if we do that we can't check
379            for errors. putenv/setenv can fail when out of memory */
380
381         if (!EnvironPutenv (pid_buf, FALSE) || !EnvironPutenv (exe_buf, FALSE))
382         {
383             goto FAILED;
384         }
385
386         if (run_debug_command (command_string))
387         {
388             goto FAILED;
389         }
390
391         free(command_string);
392         return 1;
393     }
394
395     return 0;
396
397 FAILED:
398     if (command_string)
399     {
400         free(command_string);
401     }
402
403     fprintf (stderr, "Failed to execute command: '%s'\n", command_string);
404     return -1;
405 #else // ENABLE_RUN_ON_DEBUG_BREAK
406     return 0;
407 #endif // ENABLE_RUN_ON_DEBUG_BREAK
408 }
409
410 /*++
411 Function:
412   DebugBreak
413
414 See MSDN doc.
415 --*/
416 VOID
417 PALAPI
418 DebugBreak(
419        VOID)
420 {
421     PERF_ENTRY(DebugBreak);
422     ENTRY("DebugBreak()\n");
423
424     if (DebugBreakCommand() <= 0) {
425         // either didn't do anything, or failed
426         TRACE("Calling DBG_DebugBreak\n");
427         DBG_DebugBreak();
428     }
429     
430     LOGEXIT("DebugBreak returns\n");
431     PERF_EXIT(DebugBreak);
432 }
433
434 /*++
435 Function:
436   IsInDebugBreak(addr)
437
438   Returns true if the address is in DBG_DebugBreak.
439
440 --*/
441 BOOL
442 IsInDebugBreak(void *addr)
443 {
444     return (addr >= (void *)DBG_DebugBreak) && (addr <= (void *)DBG_DebugBreak_End);
445 }
446
447 /*++
448 Function:
449   GetThreadContext
450
451 See MSDN doc.
452 --*/
453 BOOL
454 PALAPI
455 GetThreadContext(
456            IN HANDLE hThread,
457            IN OUT LPCONTEXT lpContext)
458 {
459     PAL_ERROR palError;
460     CPalThread *pThread;
461     CPalThread *pTargetThread;
462     IPalObject *pobjThread = NULL;
463     BOOL ret = FALSE;
464     
465     PERF_ENTRY(GetThreadContext);
466     ENTRY("GetThreadContext (hThread=%p, lpContext=%p)\n",hThread,lpContext);
467
468     pThread = InternalGetCurrentThread();
469
470     palError = InternalGetThreadDataFromHandle(
471         pThread,
472         hThread,
473         0, // THREAD_GET_CONTEXT
474         &pTargetThread,
475         &pobjThread
476         );
477
478     if (NO_ERROR == palError)
479     {
480         if (!pTargetThread->IsDummy())
481         {
482             ret = CONTEXT_GetThreadContext(
483                 GetCurrentProcessId(),
484                 pTargetThread->GetPThreadSelf(),
485                 lpContext
486                 );
487         }
488         else
489         {
490             ASSERT("Dummy thread handle passed to GetThreadContext\n");
491             pThread->SetLastError(ERROR_INVALID_HANDLE);
492         }
493     }
494     else
495     {
496         pThread->SetLastError(palError);
497     }
498
499     if (NULL != pobjThread)
500     {
501         pobjThread->ReleaseReference(pThread);
502     }
503     
504     LOGEXIT("GetThreadContext returns ret:%d\n", ret);
505     PERF_EXIT(GetThreadContext);
506     return ret;
507 }
508
509 /*++
510 Function:
511   SetThreadContext
512
513 See MSDN doc.
514 --*/
515 BOOL
516 PALAPI
517 SetThreadContext(
518            IN HANDLE hThread,
519            IN CONST CONTEXT *lpContext)
520 {
521     PAL_ERROR palError;
522     CPalThread *pThread;
523     CPalThread *pTargetThread;
524     IPalObject *pobjThread = NULL;
525     BOOL ret = FALSE;
526     
527     PERF_ENTRY(SetThreadContext);
528     ENTRY("SetThreadContext (hThread=%p, lpContext=%p)\n",hThread,lpContext);
529
530     pThread = InternalGetCurrentThread();
531
532     palError = InternalGetThreadDataFromHandle(
533         pThread,
534         hThread,
535         0, // THREAD_SET_CONTEXT
536         &pTargetThread,
537         &pobjThread
538         );
539
540     if (NO_ERROR == palError)
541     {
542         if (!pTargetThread->IsDummy())
543         {
544             ret = CONTEXT_SetThreadContext(
545                 GetCurrentProcessId(),
546                 pTargetThread->GetPThreadSelf(),
547                 lpContext
548                 );
549         }
550         else
551         {
552             ASSERT("Dummy thread handle passed to SetThreadContext\n");
553             pThread->SetLastError(ERROR_INVALID_HANDLE);
554         }
555     }
556     else
557     {
558         pThread->SetLastError(palError);
559     }
560
561     if (NULL != pobjThread)
562     {
563         pobjThread->ReleaseReference(pThread);
564     }
565         
566     return ret;
567 }
568
569 #if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
570 /*++
571 Function:
572   DBGWriteProcMem_Int
573
574 Abstract
575   write one int to a process memory address
576
577 Parameter
578   processId : process handle
579   addr : memory address where the int should be written
580   data : int to be written in addr
581
582 Return
583   Return 1 if it succeeds, or 0 if it's fails
584 --*/
585 static
586 int
587 DBGWriteProcMem_Int(IN DWORD processId, 
588                     IN int *addr,
589                     IN int data)
590 {
591     if (PAL_PTRACE( PAL_PT_WRITE_D, processId, addr, data ) == -1)
592     {
593         if (errno == EFAULT) 
594         {
595             ERROR("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
596                   "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
597             SetLastError(ERROR_INVALID_ADDRESS);
598         }
599         else
600         {
601             ASSERT("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
602                   "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
603             SetLastError(ERROR_INTERNAL_ERROR);
604         }
605         return 0;
606     }
607
608     return 1;
609 }
610
611 /*++
612 Function:
613   DBGWriteProcMem_IntWithMask
614
615 Abstract
616   write one int to a process memory address space using mask
617
618 Parameter
619   processId : process ID
620   addr : memory address where the int should be written
621   data : int to be written in addr
622   mask : the mask used to write only a parts of data
623
624 Return
625   Return 1 if it succeeds, or 0 if it's fails
626 --*/
627 static
628 int
629 DBGWriteProcMem_IntWithMask(IN DWORD processId,
630                             IN int *addr,
631                             IN int data,
632                             IN unsigned int mask )
633 {
634     int readInt;
635
636     if (mask != ~0)
637     {
638         errno = 0;
639         if (((readInt = PAL_PTRACE( PAL_PT_READ_D, processId, addr, 0 )) == -1)
640              && errno)
641         {
642             if (errno == EFAULT) 
643             {
644                 ERROR("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
645                       "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
646                 SetLastError(ERROR_INVALID_ADDRESS);
647             }
648             else
649             {
650                 ASSERT("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
651                       "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
652                 SetLastError(ERROR_INTERNAL_ERROR);
653             }
654
655             return 0;
656         }
657         data = (data & mask) | (readInt & ~mask);
658     }    
659     return DBGWriteProcMem_Int(processId, addr, data);
660 }
661 #endif  // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
662
663 #if !HAVE_VM_READ && !HAVE_PROCFS_CTL
664
665 /*++
666 Function:
667   DBGAttachProcess
668
669 Abstract  
670   
671   Attach the indicated process to the current process. 
672   
673   if the indicated process is already attached by the current process, then 
674   increment the number of attachment pending. if ot, attach it to the current 
675   process (with PT_ATTACH).
676
677 Parameter
678   hProcess : handle to process to attach to
679   processId : process ID to attach
680 Return
681   Return true if it succeeds, or false if it's fails
682 --*/
683 static
684 BOOL 
685 DBGAttachProcess(
686     CPalThread *pThread,
687     HANDLE hProcess,
688     DWORD processId
689     )
690 {
691     int attchmentCount;
692     int savedErrno;
693 #if HAVE_PROCFS_CTL
694     int fd = -1;
695     char ctlPath[1024];
696 #endif  // HAVE_PROCFS_CTL
697
698     attchmentCount = 
699         DBGSetProcessAttached(pThread, hProcess, DBG_ATTACH);
700
701     if (attchmentCount == -1)
702     {
703         /* Failed to set the process as attached */
704         goto EXIT;
705     }
706     
707     if (attchmentCount == 1)
708     {
709 #if HAVE_PROCFS_CTL
710         struct timespec waitTime;
711
712         // FreeBSD has some trouble when a series of attach/detach sequences
713         // occurs too close together.  When this happens, we'll be able to
714         // attach to the process, but waiting for the process to stop
715         // (either via writing "wait" to /proc/<pid>/ctl or via waitpid)
716         // will hang.  If we pause for a very short amount of time before
717         // trying to attach, we don't run into this situation.
718         waitTime.tv_sec = 0;
719         waitTime.tv_nsec = 50000000;
720         nanosleep(&waitTime, NULL);
721         
722         sprintf_s(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
723         fd = InternalOpen(ctlPath, O_WRONLY);
724         if (fd == -1)
725         {
726             ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
727                   errno, strerror(errno));
728             goto DETACH1;
729         }
730         
731         if (write(fd, CTL_ATTACH, sizeof(CTL_ATTACH)) < (int)sizeof(CTL_ATTACH))
732         {
733             ERROR("Failed to attach to %s: errno is %d (%s)\n", ctlPath,
734                   errno, strerror(errno));
735             close(fd);
736             goto DETACH1;
737         }
738         
739         if (write(fd, CTL_WAIT, sizeof(CTL_WAIT)) < (int)sizeof(CTL_WAIT))
740         {
741             ERROR("Failed to wait for %s: errno is %d (%s)\n", ctlPath,
742                   errno, strerror(errno));
743             goto DETACH2;
744         }
745         
746         close(fd);
747 #elif HAVE_TTRACE
748         if (ttrace(TT_PROC_ATTACH, processId, 0, TT_DETACH_ON_EXIT, TT_VERSION, 0) == -1)
749         {
750             if (errno != ESRCH)
751             {                
752                 ASSERT("ttrace(TT_PROC_ATTACH, pid:%d) failed errno:%d (%s)\n",
753                      processId, errno, strerror(errno));
754             }
755             goto DETACH1;
756         }
757 #else   // HAVE_TTRACE
758         if (PAL_PTRACE( PAL_PT_ATTACH, processId, 0, 0 ) == -1)
759         {
760             if (errno != ESRCH)
761             {                
762                 ASSERT("ptrace(PT_ATTACH, pid:%d) failed errno:%d (%s)\n",
763                      processId, errno, strerror(errno));
764             }
765             goto DETACH1;
766         }
767                     
768         if (waitpid(processId, NULL, WUNTRACED) == -1)
769         {
770             if (errno != ESRCH)
771             {
772                 ASSERT("waitpid(pid:%d, NULL, WUNTRACED) failed.errno:%d"
773                        " (%s)\n", processId, errno, strerror(errno));
774             }
775             goto DETACH2;
776         }
777 #endif  // HAVE_PROCFS_CTL
778     }
779     
780     return TRUE;
781
782 #if HAVE_PROCFS_CTL
783 DETACH2:
784     if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
785     {
786         ASSERT("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
787                errno, strerror(errno));
788     }
789     close(fd);
790 #elif !HAVE_TTRACE
791 DETACH2:
792     if (PAL_PTRACE(PAL_PT_DETACH, processId, 0, 0) == -1)
793     {
794         ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n", processId, 
795               errno, strerror(errno));
796     }
797 #endif  // HAVE_PROCFS_CTL
798
799 DETACH1:
800     savedErrno = errno;
801     DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);
802     errno = savedErrno;
803 EXIT:
804     if (errno == ESRCH || errno == ENOENT || errno == EBADF)
805     {
806         ERROR("Invalid process ID:%d\n", processId);
807         SetLastError(ERROR_INVALID_PARAMETER);
808     }
809     else
810     {
811         SetLastError(ERROR_INTERNAL_ERROR);
812     }
813     return FALSE;
814 }
815
816 /*++
817 Function:
818   DBGDetachProcess
819
820 Abstract
821   Detach the indicated process from the current process.
822   
823   if the indicated process is already attached by the current process, then 
824   decrement the number of attachment pending and detach it from the current 
825   process (with PT_DETACH) if there's no more attachment left. 
826   
827 Parameter
828   hProcess : process handle
829   processId : process ID
830
831 Return
832   Return true if it succeeds, or true if it's fails
833 --*/
834 static
835 BOOL
836 DBGDetachProcess(
837     CPalThread *pThread,
838     HANDLE hProcess,
839     DWORD processId
840     )
841 {     
842     int nbAttachLeft;
843 #if HAVE_PROCFS_CTL
844     int fd = -1;
845     char ctlPath[1024];
846 #endif  // HAVE_PROCFS_CTL
847
848     nbAttachLeft = DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);    
849
850     if (nbAttachLeft == -1)
851     {
852         /* Failed to set the process as detached */
853         return FALSE;
854     }
855     
856     /* check if there's no more attachment left on processId */
857     if (nbAttachLeft == 0)
858     {
859 #if HAVE_PROCFS_CTL
860         sprintf(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
861         fd = InternalOpen(pThread, ctlPath, O_WRONLY);
862         if (fd == -1)
863         {
864             if (errno == ENOENT)
865             {
866                 ERROR("Invalid process ID: %d\n", processId);
867                 SetLastError(ERROR_INVALID_PARAMETER);
868             }
869             else
870             {
871                 ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
872                       errno, strerror(errno));
873                 SetLastError(ERROR_INTERNAL_ERROR);
874             }
875             return FALSE;
876         }
877         
878         if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
879         {
880             ERROR("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
881                   errno, strerror(errno));
882             close(fd);
883             return FALSE;
884         }
885         close(fd);
886
887 #elif HAVE_TTRACE  
888         if (ttrace(TT_PROC_DETACH, processId, 0, 0, 0, 0) == -1)
889         {
890             if (errno == ESRCH)
891             {
892                 ERROR("Invalid process ID: %d\n", processId);
893                 SetLastError(ERROR_INVALID_PARAMETER);
894             }
895             else
896             {
897                 ASSERT("ttrace(TT_PROC_DETACH, pid:%d) failed. errno:%d (%s)\n", 
898                       processId, errno, strerror(errno));
899                 SetLastError(ERROR_INTERNAL_ERROR);
900             }
901             return FALSE;
902         }
903 #else   // HAVE_TTRACE
904         if (PAL_PTRACE(PAL_PT_DETACH, processId, 1, 0) == -1)
905         {            
906             if (errno == ESRCH)
907             {
908                 ERROR("Invalid process ID: %d\n", processId);
909                 SetLastError(ERROR_INVALID_PARAMETER);
910             }
911             else
912             {
913                 ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n", 
914                       processId, errno, strerror(errno));
915                 SetLastError(ERROR_INTERNAL_ERROR);
916             }
917             return FALSE;
918         }
919 #endif  // HAVE_PROCFS_CTL
920
921 #if !HAVE_TTRACE
922         if (kill(processId, SIGCONT) == -1)
923         {
924             ERROR("Failed to continue the detached process:%d errno:%d (%s)\n",
925                   processId, errno, strerror(errno));
926             return FALSE;
927         }
928 #endif  // !HAVE_TTRACE        
929     }
930     return TRUE;
931 }
932
933 /*++
934 Function:
935   DBGSetProcessAttached
936
937 Abstract
938   saves the current process Id in the attached process structure
939
940 Parameter
941   hProcess : process handle
942   bAttach : true (false) to set the process as attached (as detached)
943 Return
944  returns the number of attachment left on attachedProcId, or -1 if it fails
945 --*/
946 static int
947 DBGSetProcessAttached(
948     CPalThread *pThread,
949     HANDLE hProcess,
950     BOOL  bAttach
951     )
952 {
953     PAL_ERROR palError = NO_ERROR;
954     IPalObject *pobjProcess = NULL;
955     IDataLock *pDataLock = NULL;
956     CProcProcessLocalData *pLocalData = NULL;
957     int ret = -1;
958     CAllowedObjectTypes aotProcess(otiProcess);
959
960     palError = g_pObjectManager->ReferenceObjectByHandle(
961         pThread,
962         hProcess,
963         &aotProcess,
964         0,
965         &pobjProcess
966         );
967
968     if (NO_ERROR != palError)
969     {
970         goto DBGSetProcessAttachedExit;
971     }
972
973     palError = pobjProcess->GetProcessLocalData(
974         pThread,
975         WriteLock,
976         &pDataLock,
977         reinterpret_cast<void **>(&pLocalData)
978         );
979
980     if (NO_ERROR != palError)
981     {
982         goto DBGSetProcessAttachedExit;
983     }
984
985     if (bAttach)
986     {
987         pLocalData->lAttachCount += 1;
988     }
989     else
990     {
991         pLocalData->lAttachCount -= 1;
992
993         if (pLocalData->lAttachCount < 0)
994         {
995             ASSERT("pLocalData->lAttachCount < 0 check for extra DBGDetachProcess calls\n");
996             palError = ERROR_INTERNAL_ERROR;
997             goto DBGSetProcessAttachedExit;
998         }
999     }
1000
1001     ret = pLocalData->lAttachCount;
1002     
1003 DBGSetProcessAttachedExit:
1004
1005     if (NULL != pDataLock)
1006     {
1007         pDataLock->ReleaseLock(pThread, TRUE);
1008     }
1009
1010     if (NULL != pobjProcess)
1011     {
1012         pobjProcess->ReleaseReference(pThread);
1013     }
1014     
1015     return ret;
1016 }
1017
1018 #endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
1019
1020 /*++
1021 Function:
1022   PAL_CreateExecWatchpoint
1023
1024 Abstract
1025   Creates an OS exec watchpoint for the specified instruction
1026   and thread. This function should only be called on architectures
1027   that do not support a hardware single-step mode (e.g., SPARC).
1028
1029 Parameter
1030   hThread : the thread for which the watchpoint is to apply
1031   pvInstruction : the instruction on which the watchpoint is to be set
1032
1033 Return
1034   A Win32 error code
1035 --*/
1036
1037 DWORD
1038 PAL_CreateExecWatchpoint(
1039     HANDLE hThread,
1040     PVOID pvInstruction
1041     )
1042 {
1043     PERF_ENTRY(PAL_CreateExecWatchpoint);
1044     ENTRY("PAL_CreateExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction);
1045
1046     DWORD dwError = ERROR_NOT_SUPPORTED;
1047
1048 #if HAVE_PRWATCH_T
1049
1050     CPalThread *pThread = NULL;
1051     CPalThread *pTargetThread = NULL;
1052     IPalObject *pobjThread = NULL;
1053     int fd = -1;
1054     char ctlPath[50];
1055
1056     struct
1057     {
1058         long ctlCode;
1059         prwatch_t prwatch;
1060     } ctlStruct;
1061
1062     //
1063     // We must never set a watchpoint on an instruction that enters a syscall;
1064     // if such a request comes in we succeed it w/o actually creating the
1065     // watchpoint. This mirrors the behavior of setting the single-step flag
1066     // in a thread context when the thread is w/in a system service -- the
1067     // flag is ignored and will not be present when the thread returns
1068     // to user mode.
1069     //
1070
1071 #if defined(_SPARC_)
1072     if (*(DWORD*)pvInstruction == 0x91d02008) // ta 8
1073     {
1074         TRACE("Watchpoint requested on sysenter instruction -- ignoring");
1075         dwError = ERROR_SUCCESS;
1076         goto PAL_CreateExecWatchpointExit;        
1077     }
1078 #else
1079 #error Need syscall instruction for this platform
1080 #endif // _SPARC_
1081
1082     pThread = InternalGetCurrentThread();
1083
1084     dwError = InternalGetThreadDataFromHandle(
1085         pThread,
1086         hThread,
1087         0, // THREAD_SET_CONTEXT
1088         &pTargetThread,
1089         &pobjThread
1090         );
1091
1092     if (NO_ERROR != dwError)
1093     {
1094         goto PAL_CreateExecWatchpointExit;
1095     }
1096
1097     snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId());
1098
1099     fd = InternalOpen(pThread, ctlPath, O_WRONLY);
1100     if (-1 == fd)
1101     {
1102         ERROR("Failed to open %s\n", ctlPath);
1103         dwError = ERROR_INVALID_ACCESS;
1104         goto PAL_CreateExecWatchpointExit;
1105     }
1106
1107     ctlStruct.ctlCode = PCWATCH;
1108     ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction;
1109     ctlStruct.prwatch.pr_size = sizeof(DWORD);
1110     ctlStruct.prwatch.pr_wflags = WA_EXEC | WA_TRAPAFTER;
1111
1112     if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct))
1113     {
1114         ERROR("Failure writing control structure (errno = %u)\n", errno);
1115         dwError = ERROR_INTERNAL_ERROR;
1116         goto PAL_CreateExecWatchpointExit;
1117     }
1118
1119     dwError = ERROR_SUCCESS;
1120     
1121 PAL_CreateExecWatchpointExit:
1122
1123     if (NULL != pobjThread)
1124     {
1125         pobjThread->ReleaseReference(pThread);
1126     }
1127
1128     if (-1 != fd)
1129     {
1130         close(fd);
1131     }
1132
1133 #endif // HAVE_PRWATCH_T     
1134     
1135     LOGEXIT("PAL_CreateExecWatchpoint returns ret:%d\n", dwError);
1136     PERF_EXIT(PAL_CreateExecWatchpoint);
1137     return dwError;
1138 }
1139
1140 /*++
1141 Function:
1142   PAL_DeleteExecWatchpoint
1143
1144 Abstract
1145   Deletes an OS exec watchpoint for the specified instruction
1146   and thread. This function should only be called on architectures
1147   that do not support a hardware single-step mode (e.g., SPARC).
1148
1149 Parameter
1150   hThread : the thread to remove the watchpoint from
1151   pvInstruction : the instruction for which the watchpoint is to be removed
1152
1153 Return
1154   A Win32 error code. Attempting to delete a watchpoint that does not exist
1155   may or may not result in an error, depending on the behavior of the
1156   underlying operating system.
1157 --*/
1158
1159 DWORD
1160 PAL_DeleteExecWatchpoint(
1161     HANDLE hThread,
1162     PVOID pvInstruction
1163     )
1164 {
1165     PERF_ENTRY(PAL_DeleteExecWatchpoint);
1166     ENTRY("PAL_DeleteExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction);
1167
1168     DWORD dwError = ERROR_NOT_SUPPORTED;
1169
1170 #if HAVE_PRWATCH_T
1171
1172     CPalThread *pThread = NULL;
1173     CPalThread *pTargetThread = NULL;
1174     IPalObject *pobjThread = NULL;
1175     int fd = -1;
1176     char ctlPath[50];
1177
1178     struct
1179     {
1180         long ctlCode;
1181         prwatch_t prwatch;
1182     } ctlStruct;
1183
1184
1185     pThread = InternalGetCurrentThread();
1186
1187     dwError = InternalGetThreadDataFromHandle(
1188         pThread,
1189         hThread,
1190         0, // THREAD_SET_CONTEXT
1191         &pTargetThread,
1192         &pobjThread
1193         );
1194
1195     if (NO_ERROR != dwError)
1196     {
1197         goto PAL_DeleteExecWatchpointExit;
1198     }
1199
1200     snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId());
1201
1202     fd = InternalOpen(pThread, ctlPath, O_WRONLY);
1203     if (-1 == fd)
1204     {
1205         ERROR("Failed to open %s\n", ctlPath);
1206         dwError = ERROR_INVALID_ACCESS;
1207         goto PAL_DeleteExecWatchpointExit;
1208     }
1209
1210     ctlStruct.ctlCode = PCWATCH;
1211     ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction;
1212     ctlStruct.prwatch.pr_size = sizeof(DWORD);
1213     ctlStruct.prwatch.pr_wflags = 0;
1214
1215     if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct))
1216     {
1217         ERROR("Failure writing control structure (errno = %u)\n", errno);
1218         dwError = ERROR_INTERNAL_ERROR;
1219         goto PAL_DeleteExecWatchpointExit;
1220     }
1221
1222     dwError = ERROR_SUCCESS;
1223     
1224 PAL_DeleteExecWatchpointExit:
1225
1226     if (NULL != pobjThread)
1227     {
1228         pobjThread->ReleaseReference(pThread);
1229     }
1230
1231     if (-1 != fd)
1232     {
1233         close(fd);
1234     }
1235
1236 #endif // HAVE_PRWATCH_T    
1237     
1238     LOGEXIT("PAL_DeleteExecWatchpoint returns ret:%d\n", dwError);
1239     PERF_EXIT(PAL_DeleteExecWatchpoint);
1240     return dwError;
1241 }
1242
1243 // We want to enable hardware exception handling for ReadProcessMemory
1244 // and WriteProcessMemory in all cases since it is acceptable if they
1245 // hit AVs, so redefine HardwareExceptionHolder for these two functions
1246 // (here to the end of the file).
1247 #undef HardwareExceptionHolder
1248 #define HardwareExceptionHolder CatchHardwareExceptionHolder __catchHardwareException;
1249
1250 /*++
1251 Function:
1252   ReadProcessMemory
1253
1254 See MSDN doc.
1255 --*/
1256 BOOL
1257 PALAPI
1258 ReadProcessMemory(
1259            IN HANDLE hProcess,
1260            IN LPCVOID lpBaseAddress,
1261            IN LPVOID lpBuffer,
1262            IN SIZE_T nSize,
1263            OUT SIZE_T * lpNumberOfBytesRead
1264            )
1265 {
1266     CPalThread *pThread;
1267     DWORD processId;
1268     Volatile<BOOL> ret = FALSE;
1269     Volatile<SIZE_T> numberOfBytesRead = 0;
1270 #if HAVE_VM_READ
1271     kern_return_t result;
1272     vm_map_t task;
1273     LONG_PTR bytesToRead;
1274 #elif HAVE_PROCFS_CTL
1275     int fd = -1;
1276     char memPath[64];
1277     off_t offset;
1278 #elif !HAVE_TTRACE
1279     SIZE_T nbInts;
1280     int* ptrInt;
1281     int* lpTmpBuffer;
1282 #endif
1283 #if !HAVE_PROCFS_CTL && !HAVE_TTRACE
1284     int* lpBaseAddressAligned;
1285     SIZE_T offset;
1286 #endif  // !HAVE_PROCFS_CTL && !HAVE_TTRACE
1287
1288     PERF_ENTRY(ReadProcessMemory);
1289     ENTRY("ReadProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
1290           "nSize=%u, lpNumberOfBytesRead=%p)\n",hProcess,lpBaseAddress,
1291           lpBuffer, (unsigned int)nSize, lpNumberOfBytesRead);
1292
1293     pThread = InternalGetCurrentThread();
1294     
1295     if (!(processId = PROCGetProcessIDFromHandle(hProcess)))
1296     {
1297         ERROR("Invalid process handler hProcess:%p.",hProcess);
1298         SetLastError(ERROR_INVALID_HANDLE);
1299         goto EXIT;
1300     }
1301     
1302     // Check if the read request is for the current process. 
1303     // We don't need ptrace in that case.
1304     if (GetCurrentProcessId() == processId) 
1305     {
1306         TRACE("We are in the same process, so ptrace is not needed\n");
1307         
1308         struct Param
1309         {
1310             LPCVOID lpBaseAddress;
1311             LPVOID lpBuffer;
1312             SIZE_T nSize;
1313             SIZE_T numberOfBytesRead;
1314             BOOL ret;
1315         } param;
1316         param.lpBaseAddress = lpBaseAddress;
1317         param.lpBuffer = lpBuffer;
1318         param.nSize = nSize;
1319         param.numberOfBytesRead = numberOfBytesRead;
1320         param.ret = ret;
1321
1322         PAL_TRY(Param *, pParam, &param)
1323         {
1324             SIZE_T i;
1325             
1326             // Seg fault in memcpy can't be caught
1327             // so we simulate the memcpy here
1328
1329             for (i = 0; i<pParam->nSize; i++)
1330             {
1331                 *((char*)(pParam->lpBuffer)+i) = *((char*)(pParam->lpBaseAddress)+i);
1332             }
1333
1334             pParam->numberOfBytesRead = pParam->nSize;
1335             pParam->ret = TRUE;
1336         }
1337         PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1338         {
1339             SetLastError(ERROR_ACCESS_DENIED);
1340         }
1341         PAL_ENDTRY
1342
1343         numberOfBytesRead = param.numberOfBytesRead;
1344         ret = param.ret;
1345         goto EXIT;
1346     }
1347
1348 #if HAVE_VM_READ
1349     result = task_for_pid(mach_task_self(), processId, &task);
1350     if (result != KERN_SUCCESS)
1351     {
1352         ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
1353         SetLastError(ERROR_INVALID_HANDLE);
1354         goto EXIT;
1355     }
1356     // vm_read_overwrite usually requires that the address be page-aligned
1357     // and the size be a multiple of the page size.  We can't differentiate
1358     // between the cases in which that's required and those in which it
1359     // isn't, so we do it all the time.
1360     lpBaseAddressAligned = (int*)((SIZE_T) lpBaseAddress & ~VIRTUAL_PAGE_MASK);
1361     offset = ((SIZE_T) lpBaseAddress & VIRTUAL_PAGE_MASK);
1362     char *data;
1363     data = (char*)alloca(VIRTUAL_PAGE_SIZE);
1364     while (nSize > 0)
1365     {
1366         vm_size_t bytesRead;
1367         
1368         bytesToRead = VIRTUAL_PAGE_SIZE - offset;
1369         if (bytesToRead > (LONG_PTR)nSize)
1370         {
1371             bytesToRead = nSize;
1372         }
1373         bytesRead = VIRTUAL_PAGE_SIZE;
1374         result = vm_read_overwrite(task, (vm_address_t) lpBaseAddressAligned,
1375                                    VIRTUAL_PAGE_SIZE, (vm_address_t) data, &bytesRead);
1376         if (result != KERN_SUCCESS || bytesRead != VIRTUAL_PAGE_SIZE)
1377         {
1378             ERROR("vm_read_overwrite failed for %d bytes from %p in %d: %d\n",
1379                   VIRTUAL_PAGE_SIZE, (char *) lpBaseAddressAligned, task, result);
1380             if (result <= KERN_RETURN_MAX)
1381             {
1382                 SetLastError(ERROR_INVALID_ACCESS);
1383             }
1384             else
1385             {
1386                 SetLastError(ERROR_INTERNAL_ERROR);
1387             }
1388             goto EXIT;
1389         }
1390         memcpy((LPSTR)lpBuffer + numberOfBytesRead, data + offset, bytesToRead);
1391         numberOfBytesRead.Store(numberOfBytesRead.Load() + bytesToRead);
1392         lpBaseAddressAligned = (int*)((char*)lpBaseAddressAligned + VIRTUAL_PAGE_SIZE);
1393         nSize -= bytesToRead;
1394         offset = 0;
1395     }
1396     ret = TRUE;
1397 #else   // HAVE_VM_READ
1398 #if HAVE_PROCFS_CTL
1399     snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
1400     fd = InternalOpen(memPath, O_RDONLY);
1401     if (fd == -1)
1402     {
1403         ERROR("Failed to open %s\n", memPath);
1404         SetLastError(ERROR_INVALID_ACCESS);
1405         goto PROCFSCLEANUP;
1406     }
1407
1408     //
1409     // off_t may be greater in size than void*, so first cast to
1410     // an unsigned type to ensure that no sign extension takes place
1411     //
1412
1413     offset = (off_t) (UINT_PTR) lpBaseAddress;
1414
1415     if (lseek(fd, offset, SEEK_SET) == -1)
1416     {
1417         ERROR("Failed to seek to base address\n");
1418         SetLastError(ERROR_INVALID_ACCESS);
1419         goto PROCFSCLEANUP;
1420     }
1421     
1422     numberOfBytesRead = read(fd, lpBuffer, nSize);
1423     ret = TRUE;
1424
1425 #else   // HAVE_PROCFS_CTL
1426     // Attach the process before calling ttrace/ptrace otherwise it fails.
1427     if (DBGAttachProcess(pThread, hProcess, processId))
1428     {
1429 #if HAVE_TTRACE
1430         if (ttrace(TT_PROC_RDDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
1431         {
1432             if (errno == EFAULT) 
1433             {
1434                 ERROR("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
1435                       " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
1436                       errno, strerror(errno));
1437                 
1438                 SetLastError(ERROR_ACCESS_DENIED);
1439             }
1440             else
1441             {
1442                 ASSERT("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
1443                       " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
1444                       errno, strerror(errno));
1445                 SetLastError(ERROR_INTERNAL_ERROR);
1446             }
1447
1448             goto CLEANUP1;
1449         }
1450
1451         numberOfBytesRead = nSize;
1452         ret = TRUE;
1453         
1454 #else   // HAVE_TTRACE
1455
1456         offset = (SIZE_T)lpBaseAddress % sizeof(int);
1457         lpBaseAddressAligned =  (int*)((char*)lpBaseAddress - offset);
1458         nbInts = (nSize + offset)/sizeof(int) + 
1459                  ((nSize + offset)%sizeof(int) ? 1:0);
1460         
1461         /* before transferring any data to lpBuffer we should make sure that all 
1462            data is accessible for read. so we need to use a temp buffer for that.*/
1463         if (!(lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))))
1464         {
1465             ERROR("Insufficient memory available !\n");
1466             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1467             goto CLEANUP1;
1468         }
1469         
1470         for (ptrInt = lpTmpBuffer; nbInts; ptrInt++,
1471             lpBaseAddressAligned++, nbInts--)
1472         {
1473             errno = 0;
1474             *ptrInt =
1475                 PAL_PTRACE(PAL_PT_READ_D, processId, lpBaseAddressAligned, 0);
1476             if (*ptrInt == -1 && errno) 
1477             {
1478                 if (errno == EFAULT) 
1479                 {
1480                     ERROR("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
1481                           " errno=%d (%s)\n", processId, lpBaseAddressAligned,
1482                           errno, strerror(errno));
1483                     
1484                     SetLastError(ptrInt == lpTmpBuffer ? ERROR_ACCESS_DENIED : 
1485                                                          ERROR_PARTIAL_COPY);
1486                 }
1487                 else
1488                 {
1489                     ASSERT("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
1490                           " errno=%d (%s)\n", processId, lpBaseAddressAligned,
1491                           errno, strerror(errno));
1492                     SetLastError(ERROR_INTERNAL_ERROR);
1493                 }
1494                 
1495                 goto CLEANUP2;
1496             }
1497         }
1498         
1499         /* transfer data from temp buffer to lpBuffer */
1500         memcpy( (char *)lpBuffer, ((char*)lpTmpBuffer) + offset, nSize);
1501         numberOfBytesRead = nSize;
1502         ret = TRUE;
1503 #endif // HAVE_TTRACE        
1504     }
1505     else
1506     {
1507         /* Failed to attach processId */
1508         goto EXIT;    
1509     }
1510 #endif  // HAVE_PROCFS_CTL
1511
1512 #if HAVE_PROCFS_CTL
1513 PROCFSCLEANUP:
1514     if (fd != -1)
1515     {
1516         close(fd);
1517     }    
1518 #elif !HAVE_TTRACE
1519 CLEANUP2:
1520     if (lpTmpBuffer) 
1521     {
1522         free(lpTmpBuffer);
1523     }
1524 #endif  // !HAVE_TTRACE
1525
1526 #if !HAVE_PROCFS_CTL
1527 CLEANUP1:
1528     if (!DBGDetachProcess(pThread, hProcess, processId))
1529     {
1530         /* Failed to detach processId */
1531         ret = FALSE;
1532     }
1533 #endif  // HAVE_PROCFS_CTL
1534 #endif  // HAVE_VM_READ
1535
1536 EXIT:
1537     if (lpNumberOfBytesRead)
1538     {
1539         *lpNumberOfBytesRead = numberOfBytesRead;
1540     }
1541     LOGEXIT("ReadProcessMemory returns BOOL %d\n", ret.Load());
1542     PERF_EXIT(ReadProcessMemory);
1543     return ret;
1544 }
1545
1546 /*++
1547 Function:
1548   WriteProcessMemory
1549
1550 See MSDN doc.
1551 --*/
1552 BOOL
1553 PALAPI
1554 WriteProcessMemory(
1555            IN HANDLE hProcess,
1556            IN LPVOID lpBaseAddress,
1557            IN LPCVOID lpBuffer,
1558            IN SIZE_T nSize,
1559            OUT SIZE_T * lpNumberOfBytesWritten
1560            )
1561
1562 {
1563     CPalThread *pThread;
1564     DWORD processId;
1565     Volatile<BOOL> ret = FALSE;
1566     Volatile<SIZE_T> numberOfBytesWritten = 0;
1567 #if HAVE_VM_READ
1568     kern_return_t result;
1569     vm_map_t task;
1570 #elif HAVE_PROCFS_CTL
1571     int fd = -1;
1572     char memPath[64];
1573     LONG_PTR bytesWritten;
1574     off_t offset;
1575 #elif !HAVE_TTRACE
1576     SIZE_T FirstIntOffset;
1577     SIZE_T LastIntOffset;
1578     unsigned int FirstIntMask;
1579     unsigned int LastIntMask;
1580     SIZE_T nbInts;
1581     int *lpTmpBuffer = 0, *lpInt;
1582     int* lpBaseAddressAligned;
1583 #endif
1584
1585     PERF_ENTRY(WriteProcessMemory);
1586     ENTRY("WriteProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
1587            "nSize=%u, lpNumberOfBytesWritten=%p)\n",
1588            hProcess,lpBaseAddress, lpBuffer, (unsigned int)nSize, lpNumberOfBytesWritten); 
1589
1590     pThread = InternalGetCurrentThread();
1591     
1592     if (!(nSize && (processId = PROCGetProcessIDFromHandle(hProcess))))
1593     {
1594         ERROR("Invalid nSize:%u number or invalid process handler "
1595               "hProcess:%p\n", (unsigned int)nSize, hProcess);
1596         SetLastError(ERROR_INVALID_PARAMETER);
1597         goto EXIT;
1598     }
1599     
1600     // Check if the write request is for the current process.
1601     // In that case we don't need ptrace.
1602     if (GetCurrentProcessId() == processId) 
1603     {
1604         TRACE("We are in the same process so we don't need ptrace\n");
1605         
1606         struct Param
1607         {
1608             LPVOID lpBaseAddress;
1609             LPCVOID lpBuffer;
1610             SIZE_T nSize;
1611             SIZE_T numberOfBytesWritten;
1612             BOOL ret;
1613         } param;
1614         param.lpBaseAddress = lpBaseAddress;
1615         param.lpBuffer = lpBuffer;
1616         param.nSize = nSize;
1617         param.numberOfBytesWritten = numberOfBytesWritten;
1618         param.ret = ret;
1619
1620         PAL_TRY(Param *, pParam, &param)
1621         {
1622             SIZE_T i;
1623             
1624             // Seg fault in memcpy can't be caught
1625             // so we simulate the memcpy here
1626
1627             for (i = 0; i<pParam->nSize; i++)
1628             {
1629                 *((char*)(pParam->lpBaseAddress)+i) = *((char*)(pParam->lpBuffer)+i);
1630             }
1631
1632             pParam->numberOfBytesWritten = pParam->nSize;
1633             pParam->ret = TRUE;
1634         } 
1635         PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1636         {
1637             SetLastError(ERROR_ACCESS_DENIED);
1638         }
1639         PAL_ENDTRY
1640
1641         numberOfBytesWritten = param.numberOfBytesWritten;
1642         ret = param.ret;
1643         goto EXIT;        
1644     }
1645
1646 #if HAVE_VM_READ
1647     result = task_for_pid(mach_task_self(), processId, &task);
1648     if (result != KERN_SUCCESS)
1649     {
1650         ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
1651         SetLastError(ERROR_INVALID_HANDLE);
1652         goto EXIT;
1653     }
1654     result = vm_write(task, (vm_address_t) lpBaseAddress, 
1655                       (vm_address_t) lpBuffer, nSize);
1656     if (result != KERN_SUCCESS)
1657     {
1658         ERROR("vm_write failed for %d bytes from %p in %d: %d\n",
1659               (int)nSize, lpBaseAddress, task, result);
1660         if (result <= KERN_RETURN_MAX)
1661         {
1662             SetLastError(ERROR_ACCESS_DENIED);
1663         }
1664         else
1665         {
1666             SetLastError(ERROR_INTERNAL_ERROR);
1667         }
1668         goto EXIT;
1669     }
1670     numberOfBytesWritten = nSize;
1671     ret = TRUE;
1672 #else   // HAVE_VM_READ
1673 #if HAVE_PROCFS_CTL
1674     snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
1675     fd = InternalOpen(memPath, O_WRONLY);
1676     if (fd == -1)
1677     {
1678         ERROR("Failed to open %s\n", memPath);
1679         SetLastError(ERROR_INVALID_ACCESS);
1680         goto PROCFSCLEANUP;
1681     }
1682
1683     //
1684     // off_t may be greater in size than void*, so first cast to
1685     // an unsigned type to ensure that no sign extension takes place
1686     //
1687
1688     offset = (off_t) (UINT_PTR) lpBaseAddress;
1689
1690     if (lseek(fd, offset, SEEK_SET) == -1)
1691     {
1692         ERROR("Failed to seek to base address\n");
1693         SetLastError(ERROR_INVALID_ACCESS);
1694         goto PROCFSCLEANUP;
1695     }
1696     
1697     bytesWritten = write(fd, lpBuffer, nSize);
1698     if (bytesWritten < 0)
1699     {
1700         ERROR("Failed to write to %s\n", memPath);
1701         SetLastError(ERROR_INVALID_ACCESS);
1702         goto PROCFSCLEANUP;
1703     }
1704
1705     numberOfBytesWritten = bytesWritten;
1706     ret = TRUE;
1707
1708 #else   // HAVE_PROCFS_CTL
1709     /* Attach the process before calling ptrace otherwise it fails */
1710     if (DBGAttachProcess(pThread, hProcess, processId))
1711     {
1712 #if HAVE_TTRACE
1713         if (ttrace(TT_PROC_WRDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
1714         {
1715             if (errno == EFAULT) 
1716             {
1717                 ERROR("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
1718                       " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
1719                       errno, strerror(errno));
1720                 
1721                 SetLastError(ERROR_ACCESS_DENIED);
1722             }
1723             else
1724             {
1725                 ASSERT("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
1726                       " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
1727                       errno, strerror(errno));
1728                 SetLastError(ERROR_INTERNAL_ERROR);
1729             }
1730
1731             goto CLEANUP1;
1732         }
1733
1734         numberOfBytesWritten = nSize;
1735         ret = TRUE;
1736         
1737 #else   // HAVE_TTRACE
1738
1739         FirstIntOffset = (SIZE_T)lpBaseAddress % sizeof(int);    
1740         FirstIntMask = -1;
1741         FirstIntMask <<= (FirstIntOffset * 8);
1742         
1743         nbInts = (nSize + FirstIntOffset) / sizeof(int) + 
1744                  (((nSize + FirstIntOffset)%sizeof(int)) ? 1:0);
1745         lpBaseAddressAligned = (int*)((char*)lpBaseAddress - FirstIntOffset);
1746         
1747         if ((lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))) == NULL)
1748         {
1749             ERROR("Insufficient memory available !\n");
1750             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1751             goto CLEANUP1;
1752         }
1753
1754         memcpy((char *)lpTmpBuffer + FirstIntOffset, (char *)lpBuffer, nSize);
1755         lpInt = lpTmpBuffer;
1756
1757         LastIntOffset = (nSize + FirstIntOffset) % sizeof(int);
1758         LastIntMask = -1;
1759         LastIntMask >>= ((sizeof(int) - LastIntOffset) * 8);
1760
1761         if (nbInts == 1)
1762         {
1763             if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned, 
1764                                             *lpInt,
1765                                             LastIntMask & FirstIntMask)
1766                   == 0)
1767             {
1768                 goto CLEANUP2;
1769             }
1770             numberOfBytesWritten = nSize;
1771             ret = TRUE;
1772             goto CLEANUP2;
1773         }
1774
1775         if (DBGWriteProcMem_IntWithMask(processId,
1776                                         lpBaseAddressAligned++,
1777                                         *lpInt++, FirstIntMask) 
1778             == 0)
1779         {
1780             goto CLEANUP2;
1781         }
1782
1783         while (--nbInts > 1)
1784         {      
1785           if (DBGWriteProcMem_Int(processId, lpBaseAddressAligned++,
1786                                   *lpInt++) == 0)
1787           {
1788               goto CLEANUP2;
1789           }
1790         }
1791         
1792         if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned,
1793                                         *lpInt, LastIntMask ) == 0)
1794         {
1795             goto CLEANUP2;
1796         }
1797
1798         numberOfBytesWritten = nSize;
1799         ret = TRUE;
1800 #endif  // HAVE_TTRACE
1801     }
1802     else
1803     {
1804         /* Failed to attach processId */
1805         goto EXIT;
1806     }
1807 #endif // HAVE_PROCFS_CTL
1808
1809 #if HAVE_PROCFS_CTL
1810 PROCFSCLEANUP:
1811     if (fd != -1)
1812     {
1813         close(fd);
1814     }
1815 #elif !HAVE_TTRACE
1816 CLEANUP2:
1817     if (lpTmpBuffer) 
1818     {
1819         free(lpTmpBuffer);
1820     }
1821 #endif  // !HAVE_TTRACE
1822
1823 #if !HAVE_PROCFS_CTL
1824 CLEANUP1:
1825     if (!DBGDetachProcess(pThread, hProcess, processId))
1826     {
1827         /* Failed to detach processId */
1828         ret = FALSE;
1829     }
1830 #endif  // !HAVE_PROCFS_CTL
1831 #endif  // HAVE_VM_READ
1832
1833 EXIT:
1834     if (lpNumberOfBytesWritten)
1835     {
1836         *lpNumberOfBytesWritten = numberOfBytesWritten;
1837     }
1838
1839     LOGEXIT("WriteProcessMemory returns BOOL %d\n", ret.Load());
1840     PERF_EXIT(WriteProcessMemory);
1841     return ret;
1842 }
1843
1844 } // extern "C"