]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syswrap/syswrap-ppc64-aix5.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_syswrap / syswrap-ppc64-aix5.c
1
2 /*--------------------------------------------------------------------*/
3 /*--- Platform-specific syscalls stuff.       syswrap-ppc64-aix5.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9
10    Copyright (C) 2006-2010 OpenWorks LLP
11       info@open-works.co.uk
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26    02111-1307, USA.
27
28    The GNU General Public License is contained in the file COPYING.
29
30    Neither the names of the U.S. Department of Energy nor the
31    University of California nor the names of its contributors may be
32    used to endorse or promote products derived from this software
33    without prior written permission.
34 */
35
36 #if defined(VGP_ppc64_aix5)
37
38 #include "pub_core_basics.h"
39 #include "pub_core_vki.h"
40 #include "pub_core_vkiscnums.h"
41 #include "pub_core_threadstate.h"
42 #include "pub_core_debuglog.h"
43 #include "pub_core_libcassert.h"
44 #include "pub_core_libcprint.h"
45 #include "pub_core_libcproc.h"
46 #include "pub_core_options.h"
47 #include "pub_core_scheduler.h"
48 #include "pub_core_sigframe.h"      // For VG_(sigframe_destroy)()
49 #include "pub_core_signals.h"
50 #include "pub_core_syscall.h"
51 #include "pub_core_syswrap.h"
52 #include "pub_core_tooliface.h"
53
54 #include "priv_types_n_macros.h"
55 #include "priv_syswrap-aix5.h"      /* for decls of aix5-common wrappers */
56 #include "priv_syswrap-main.h"
57
58
59 /* --------- HACKS --------- */
60 /* XXXXXXXXXXXX these HACKS are copies of stuff in syswrap-linux.c;
61    check for duplication. */
62 /* HACK: is in syswrap-generic.c, but that doesn't get build on AIX. */
63 /* Dump out a summary, and a more detailed list, of open file descriptors. */
64 void VG_(show_open_fds) ( void )
65 {
66   I_die_here;
67 }
68 static Bool i_am_the_only_thread ( void )
69 {
70    Int c = VG_(count_living_threads)();
71    vg_assert(c >= 1); /* stay sane */
72    return c == 1;
73 }
74 void VG_(reap_threads)(ThreadId self)
75 {
76    while (!i_am_the_only_thread()) {
77       /* Let other thread(s) run */
78       VG_(vg_yield)();
79       VG_(poll_signals)(self);
80    }
81    vg_assert(i_am_the_only_thread());
82 }
83 void VG_(init_preopened_fds) ( void )
84 {
85    I_die_here;
86 }
87
88
89 // Run a thread from beginning to end and return the thread's
90 // scheduler-return-code.
91 static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
92 {
93    VgSchedReturnCode ret;
94    ThreadId     tid = (ThreadId)tidW;
95    ThreadState* tst = VG_(get_ThreadState)(tid);
96
97    VG_(debugLog)(1, "syswrap-aix64",
98                     "thread_wrapper(tid=%lld): entry\n",
99                     (ULong)tidW);
100
101    vg_assert(tst->status == VgTs_Init);
102
103    /* make sure we get the CPU lock before doing anything significant */
104    VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)");
105
106    if (0)
107       VG_(printf)("thread tid %d started: stack = %p\n",
108                   tid, &tid);
109
110    VG_TRACK( pre_thread_first_insn, tid );
111
112    tst->os_state.lwpid = VG_(gettid)();
113    tst->os_state.threadgroup = VG_(getpid)();
114
115    /* Thread created with all signals blocked; scheduler will set the
116       appropriate mask */
117    ret = VG_(scheduler)(tid);
118
119    vg_assert(VG_(is_exiting)(tid));
120
121    vg_assert(tst->status == VgTs_Runnable);
122    vg_assert(VG_(is_running_thread)(tid));
123
124    VG_(debugLog)(1, "syswrap-aix64",
125                     "thread_wrapper(tid=%lld): exit\n",
126                     (ULong)tidW);
127
128    /* Return to caller, still holding the lock. */
129    return ret;
130 }
131
132
133 /* Run a thread all the way to the end, then do appropriate exit actions
134    (this is the last-one-out-turn-off-the-lights bit).  */
135 static void run_a_thread_NORETURN ( Word tidW )
136 {
137    ThreadId          tid = (ThreadId)tidW;
138    VgSchedReturnCode src;
139    Int               c;
140
141    VG_(debugLog)(1, "syswrap-aix64",
142                     "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n",
143                     (ULong)tidW);
144
145    /* Run the thread all the way through. */
146    src = thread_wrapper(tid);
147
148    VG_(debugLog)(1, "syswrap-aix64",
149                     "run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
150                     (ULong)tidW);
151
152    c = VG_(count_living_threads)();
153    vg_assert(c >= 1); /* stay sane */
154
155    vg_assert(src == VgSrc_ExitThread 
156              || src == VgSrc_ExitProcess
157              || src == VgSrc_FatalSig);
158
159    if (c == 1 || src == VgSrc_ExitProcess) {
160
161       VG_(debugLog)(1, "syswrap-aix64",
162                        "run_a_thread_NORETURN(tid=%lld): "
163                           "exit process (%d threads remaining)\n",
164                           (ULong)tidW, c);
165
166       /* We are the last one standing.  Keep hold of the lock and
167          carry on to show final tool results, then exit the entire system.
168          Use the continuation pointer set at startup in m_main. */
169       ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src);
170
171    } else {
172
173       ThreadState *tst;
174
175       VG_(debugLog)(1, "syswrap-aix64",
176                        "run_a_thread_NORETURN(tid=%lld): "
177                           "not last one standing\n",
178                           (ULong)tidW);
179
180       /* OK, thread is dead, but others still exist.  Just exit. */
181       vg_assert(c >= 2);
182       tst = VG_(get_ThreadState)(tid);
183
184       /* This releases the run lock */
185       VG_(exit_thread)(tid);
186       vg_assert(tst->status == VgTs_Zombie);
187
188       /* We have to use this sequence to terminate the thread to
189          prevent a subtle race.  If VG_(exit_thread)() had left the
190          ThreadState as Empty, then it could have been reallocated,
191          reusing the stack while we're doing these last cleanups.
192          Instead, VG_(exit_thread) leaves it as Zombie to prevent
193          reallocation.  We need to make sure we don't touch the stack
194          between marking it Empty and exiting.  Hence the
195          assembler. */
196       { ULong block[4];
197         vg_assert(sizeof(tst->status == 8));
198         vg_assert(__NR_AIX5_thread_terminate
199                   != __NR_AIX5_UNKNOWN);
200         block[0] = (ULong)VgTs_Empty;
201         block[1] = (ULong) & (tst->status);
202         block[2] = (ULong) tst->os_state.exitcode;
203         block[3] = __NR_AIX5_thread_terminate;
204         asm volatile (
205           "mr 29,%0\n\t"           /* r29 = &block[0] */
206           "ld 20, 0(29)\n\t"       /* r20 = VgTs_Empty */
207           "ld 21, 8(29)\n\t"       /* r21 = & (tst->status) */
208           "ld 22, 16(29)\n\t"      /* r22 = tst->os_state.exitcode */
209           "ld 23, 24(29)\n\t"      /* r23 = __NR_exit */
210           /* after this point we can't safely use the stack. */
211           "std 20, 0(21)\n\t"      /* tst->status = VgTs_Empty */
212           "mr 2,23\n\t"            /* r2 = __NR_exit */
213           "mr 3,22\n\t"            /* set r3 = tst->os_state.exitcode */
214           /* set up for syscall */
215           "crorc 6,6,6\n\t"
216           ".long 0x48000005\n\t"   /* "bl here+4" */
217           "mflr 29\n\t"
218           "addi 29,29,16\n\t"
219           "mtlr 29\n\t"
220           "sc\n\t"                 /* exit(tst->os_state.exitcode) */
221           :
222           : "b" (&block[0])
223           : "lr", "memory", "r2", "r3", "r20", "r21", "r22", "r23", "r29"
224         );
225       }
226
227       VG_(core_panic)("Thread exit failed?\n");
228    }
229
230    /*NOTREACHED*/
231    vg_assert(0);
232 }
233
234
235 static Word start_thread_NORETURN ( void* arg )
236 {
237    ThreadState* tst = (ThreadState*)arg;
238    ThreadId     tid = tst->tid;
239
240    run_a_thread_NORETURN ( (Word)tid );
241    /*NOTREACHED*/
242    vg_assert(0);
243 }
244
245
246 /* Call f(arg1), but first switch stacks, using 'stack' as the new
247    stack.  f itself needs to never return. */
248 __attribute__((noreturn))
249 static
250 void call_on_new_stack_0_1_NORETURN ( Addr stack,
251                                       void (*f_NORETURN)(Word),
252                                       Word arg1 )
253 {
254    UWord* fdescr = (UWord*)f_NORETURN;
255    volatile UWord block[5];
256    block[0] = fdescr[0];  /* nia */
257    block[1] = stack;      /* r1 */
258    block[2] = fdescr[1];  /* r2 */
259    block[3] = arg1;       /* r3 */
260    block[4] = fdescr[2];  /* r11 */
261    __asm__ __volatile__(
262       "mr  4,%0\n\t" /* r4 = block */
263       "ld 1, 8(4)\n\t"
264       "ld 2, 16(4)\n\t"
265       "ld 3, 24(4)\n\t"
266       "ld 11,32(4)\n\t"
267       "ld 4, 0(4)\n\t"
268       "mtctr 4\n\t"
269       "bctr\n"
270       : /*out*/ : /*in*/ "b"(&block[0]) 
271    );
272    /*NOTREACHED*/
273    __asm__ __volatile__("trap");
274    while (1) {} /* convince gcc that this really doesn't return */
275 }
276
277
278 /* Allocate a stack for the main thread, and run it all the way to the
279    end.  Although we already have a working VgStack
280    (VG_(interim_stack)) it's better to allocate a new one, so that
281    overflow detection works uniformly for all threads.
282 */
283 void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
284 {
285    Addr sp;
286    VG_(debugLog)(1, "syswrap-aix64",
287                     "entering VG_(main_thread_wrapper_NORETURN)\n");
288
289    sp = ML_(allocstack)(tid);
290
291    /* If we can't even allocate the first thread's stack, we're hosed.
292       Give up. */
293    vg_assert2(sp != 0, "Cannot allocate main thread's stack.");
294
295    /* shouldn't be any other threads around yet */
296    vg_assert( VG_(count_living_threads)() == 1 );
297
298    /* make a stack frame */
299    sp -= 16;
300    sp &= ~0xF;
301    *(UWord *)sp = 0;
302
303    call_on_new_stack_0_1_NORETURN(
304       (Addr)sp,               /* stack */
305       run_a_thread_NORETURN,  /* fn to call */
306       (Word)tid               /* arg to give it */
307    );
308
309    /*NOTREACHED*/
310    vg_assert(0);
311 }
312
313 /* --------- end HACKS --------- */
314
315
316 /* ---------------------------------------------------------------------
317    More thread stuff
318    ------------------------------------------------------------------ */
319
320 void VG_(cleanup_thread) ( ThreadArchState* arch )
321 {
322 }  
323
324
325 /* ---------------------------------------------------------------------
326    PRE/POST wrappers for ppc64/AIX5-specific syscalls
327    ------------------------------------------------------------------ */
328
329 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
330 #include <sys/thread.h>
331 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
332
333
334 /* Add prototypes for the wrappers declared here, so that gcc doesn't
335    harass us for not having prototypes.  Really this is a kludge --
336    the right thing to do is to make these wrappers 'static' since they
337    aren't visible outside this file, but that requires even more macro
338    magic. */
339
340 #define PRE(name)       DEFN_PRE_TEMPLATE(ppc64_aix5, name)
341 #define POST(name)      DEFN_POST_TEMPLATE(ppc64_aix5, name)
342
343 DECL_TEMPLATE(ppc64_aix5, sys__clock_gettime);
344 DECL_TEMPLATE(ppc64_aix5, sys__fp_fpscrx64_);
345 DECL_TEMPLATE(ppc64_aix5, sys_kload);
346 DECL_TEMPLATE(ppc64_aix5, sys_kunload64);
347 DECL_TEMPLATE(ppc64_aix5, sys_thread_setstate);
348 DECL_TEMPLATE(ppc64_aix5, sys_FAKE_SIGRETURN);
349
350
351 PRE(sys__clock_gettime)
352 {
353    /* Seems like ARG2 points at a destination buffer? */
354    /* _clock_gettime (UNDOCUMENTED) ( 0, 0xA, 0x2FF21808 ) */
355    PRINT("_clock_gettime (UNDOCUMENTED) ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3 );
356    PRE_REG_READ3(int, "_clock_gettime", int, arg1, int, arg2, void*, arg3);
357    PRE_MEM_WRITE( "_clock_gettime(dst)", ARG2, sizeof(struct timespec) );
358 }
359 POST(sys__clock_gettime)
360 {
361    vg_assert(SUCCESS);
362    POST_MEM_WRITE( ARG2, sizeof(struct timespec) );
363 }
364
365 PRE(sys__fp_fpscrx64_)
366 {
367    PRINT("_fp_fpscrx64_ (BOGUS HANDLER)");
368 }
369
370 PRE(sys_kload)
371 {
372    PRINT("kload (UNDOCUMENTED)( %#lx(%s), %ld, %ld )", 
373          ARG1,(Char*)ARG1, ARG2, ARG3 );
374    PRE_REG_READ3(void*, "kload", char*, name, long, arg2, char*, arg3);
375 }
376 POST(sys_kload)
377 {
378    vg_assert(SUCCESS);
379    if (0) VG_(printf)("kload result = %#lx\n", RES);
380    if (RES)
381       POST_MEM_WRITE( RES, 64 );
382    ML_(aix5_rescan_procmap_after_load_or_unload)();
383 }
384
385 PRE(sys_kunload64)
386 {
387    PRINT("kunload64 (UNDOCUMENTED)( %#lx, %ld, %ld, %#lx )", 
388          ARG1, ARG2, ARG3, ARG4 );
389    PRE_REG_READ4(long, "kunload64",
390                  void*, arg1, long, arg2, long, arg3, void*, arg4);
391 }
392 POST(sys_kunload64)
393 {
394    vg_assert(SUCCESS);
395    ML_(aix5_rescan_procmap_after_load_or_unload)();
396 }
397
398 PRE(sys_thread_setstate)
399 {
400    UWord          dst_lwpid = (UWord)ARG1;
401    struct tstate* ats_new   = (struct tstate*)ARG2;
402    struct tstate* ats_old   = (struct tstate*)ARG3;
403    ThreadId       dst_tid   = VG_INVALID_THREADID;
404    ThreadState*   dst_ts    = NULL;
405    Int i;
406
407    /* Arrgh.  We MUST retain the lock during this syscall.  Reason is
408       that this is sometimes used for asynchronous thread cancellation
409       (nuking other threads).  If we don't have the lock during the
410       syscall, then it's possible that the thread we're nuking might
411       get the lock before it gets killed off, and so we can never
412       re-acquire the lock after this syscall, and the system
413       deadlocks. */
414
415    /* 10 July 06: above comment is a misdiagnosis.  It appears that
416       for thread cancellation (that is, with ->flags == TSTATE_INTR)
417       the target thread is has its PC changed by the the kernel to
418       something else, possibly to pthread_exit(), so that it can run
419       its cancellation handlers and exit.  Currently is unknown how
420       the kernel knows what to set the target thread's PC to.  I did
421       establish that all the other data passed in the struct is not
422       relevant: when ->flags == TSTATE_INTR, all the other words can
423       be set to 0x0 or 0xFFFFFFFF and the syscall still works.  So the
424       address is not passed like that.  Also I looked at args to
425       thread_setmystate_fast, which is used when a thread sets its
426       cancellation state, but none of those are code addresses.
427
428       Also, it's ok for the kernel to simply change the target
429       thread's PC to something else for async thread cancellation, but
430       for deferred cancellation something else is needed, and I can't
431       see how that would work either.
432
433       Anyway, net result is, target thread ends up not running on the
434       simulator (not dead), which is why it's necessary to hold onto
435       the lock at this point. */
436
437    /* 30 July 06: added kludge to intercept attempts to cancel another
438       thread and instead just force that thread to run
439       pthread_exit(PTHREAD_CANCELED).  This allows V to keep
440       control. */
441
442    PRINT("thread_setstate (BOGUS HANDLER) "
443          "( %ld, %p,%p )", dst_lwpid, ats_new, ats_old);
444    if (1 && VG_(clo_trace_syscalls) && ats_new)
445       ML_(aix5debugstuff_show_tstate)((Addr)ats_new, 
446                                       "thread_setstate (NEW)");
447
448    /* Intercept and handle ourselves any attempts to cancel 
449       another thread (including this one). */
450
451    if (ats_new && (!ats_old) && ats_new->flags == TSTATE_INTR) {
452       dst_ts = NULL;
453       if (VG_(clo_trace_syscalls))
454          VG_(printf)("(INTR for lwpid %ld)", dst_lwpid);
455       dst_tid = VG_INVALID_THREADID;
456       for (i = 0; i < VG_N_THREADS; i++) {
457          dst_ts = VG_(get_ThreadState)(i);
458          if ((dst_ts->status == VgTs_Runnable 
459               || dst_ts->status == VgTs_Yielding
460               || dst_ts->status == VgTs_WaitSys)
461              && dst_ts->os_state.lwpid == dst_lwpid) {
462             dst_tid = i;
463             break;
464          }
465       }
466       if (VG_(clo_trace_syscalls)) {
467          if (dst_tid == VG_INVALID_THREADID)
468             VG_(printf)("(== unknown tid)");
469          else 
470             VG_(printf)("(== tid %d)", (Int)dst_tid);
471       }
472       if (dst_tid != VG_INVALID_THREADID) {
473          /* A cancel has been requested for ctid.  If the target
474             thread has cancellation enabled, honour it right now.  If
475             not, mark the thread as having a cancellation request, so
476             that if it later enables cancellation then the
477             cancellation will take effect. */
478          vg_assert(dst_ts);
479          if (dst_ts->os_state.cancel_progress == Canc_NoRequest) {
480             if (dst_ts->os_state.cancel_disabled) {
481                if (VG_(clo_trace_syscalls))
482                   VG_(printf)("(target has cancel disabled"
483                               "; request lodged)");
484                dst_ts->os_state.cancel_progress = Canc_Requested;
485             } else {
486                if (VG_(clo_trace_syscalls))
487                   VG_(printf)("(forcing target into pthread_exit)");
488                dst_ts->os_state.cancel_progress = Canc_Actioned;
489                Bool ok = ML_(aix5_force_thread_into_pthread_exit)(dst_tid);
490                if (!ok) {
491                   /* now at serious risk of deadlock/livelock.  Give up
492                      rather than continue. */
493                   ML_(aix5_set_threadstate_for_emergency_exit)
494                      (tid, "pthread_cancel(case2-64): "
495                            "cannot find pthread_exit; aborting");
496                   SET_STATUS_Success(0);
497                   return;
498                }
499             }
500          }
501          SET_STATUS_Success(0);
502          return;
503       }
504    }
505
506    /* Well, it's not a cancellation request.  Maybe it is the
507       initialisation of a previously created thread? */
508
509    if (ats_new && !ats_old) {
510       dst_tid = VG_INVALID_THREADID;
511       for (i = 0; i < VG_N_THREADS; i++) {
512          dst_ts = VG_(get_ThreadState)(i);
513          if (dst_ts->status == VgTs_Init 
514              && dst_ts->os_state.lwpid == dst_lwpid) {
515             dst_tid = i;
516             break;
517          }
518       }
519       if (dst_tid != VG_INVALID_THREADID) {
520          /* Found the associated child */
521          if (VG_(clo_trace_syscalls)) 
522             VG_(printf)("(initialised child tid %d)", (Int)dst_tid);
523          dst_ts = VG_(get_ThreadState)(dst_tid);
524          UWord* stack = (UWord*)ML_(allocstack)(dst_tid);
525          /* XXX TODO: check allocstack failure */
526
527          /* copy the specified child register state into the guest
528             slot (we need that context to run on the simulated CPU,
529             not the real one) and put pointers to our own
530             run-the-simulator function into what we'll hand off to the
531             kernel instead. */
532
533          /* The guest thread is to start running whatever context
534             this syscall showed up with. */
535          dst_ts->arch.vex.guest_GPR0  = ats_new->mst.gpr[0];
536          dst_ts->arch.vex.guest_GPR1  = ats_new->mst.gpr[1]; /* sp */
537          dst_ts->arch.vex.guest_GPR2  = ats_new->mst.gpr[2]; /* toc */
538          dst_ts->arch.vex.guest_GPR3  = ats_new->mst.gpr[3]; /* initarg */
539          dst_ts->arch.vex.guest_GPR4  = ats_new->mst.gpr[4];
540          dst_ts->arch.vex.guest_GPR5  = ats_new->mst.gpr[5];
541          dst_ts->arch.vex.guest_GPR6  = ats_new->mst.gpr[6];
542          dst_ts->arch.vex.guest_GPR7  = ats_new->mst.gpr[7];
543          dst_ts->arch.vex.guest_GPR8  = ats_new->mst.gpr[8];
544          dst_ts->arch.vex.guest_GPR9  = ats_new->mst.gpr[9];
545          dst_ts->arch.vex.guest_GPR10 = ats_new->mst.gpr[10];
546          dst_ts->arch.vex.guest_GPR11 = ats_new->mst.gpr[11]; /* ?? */
547          dst_ts->arch.vex.guest_GPR12 = ats_new->mst.gpr[12];
548          dst_ts->arch.vex.guest_GPR13 = ats_new->mst.gpr[13];
549          dst_ts->arch.vex.guest_GPR14 = ats_new->mst.gpr[14];
550          dst_ts->arch.vex.guest_GPR15 = ats_new->mst.gpr[15];
551          dst_ts->arch.vex.guest_GPR16 = ats_new->mst.gpr[16];
552          dst_ts->arch.vex.guest_GPR17 = ats_new->mst.gpr[17];
553          dst_ts->arch.vex.guest_GPR18 = ats_new->mst.gpr[18];
554          dst_ts->arch.vex.guest_GPR19 = ats_new->mst.gpr[19];
555          dst_ts->arch.vex.guest_GPR20 = ats_new->mst.gpr[20];
556          dst_ts->arch.vex.guest_GPR21 = ats_new->mst.gpr[21];
557          dst_ts->arch.vex.guest_GPR22 = ats_new->mst.gpr[22];
558          dst_ts->arch.vex.guest_GPR23 = ats_new->mst.gpr[23];
559          dst_ts->arch.vex.guest_GPR24 = ats_new->mst.gpr[24];
560          dst_ts->arch.vex.guest_GPR25 = ats_new->mst.gpr[25];
561          dst_ts->arch.vex.guest_GPR26 = ats_new->mst.gpr[26];
562          dst_ts->arch.vex.guest_GPR27 = ats_new->mst.gpr[27];
563          dst_ts->arch.vex.guest_GPR28 = ats_new->mst.gpr[28];
564          dst_ts->arch.vex.guest_GPR29 = ats_new->mst.gpr[29];
565          dst_ts->arch.vex.guest_GPR30 = ats_new->mst.gpr[30];
566          dst_ts->arch.vex.guest_GPR31 = ats_new->mst.gpr[31];
567          dst_ts->arch.vex.guest_CIA   = ats_new->mst.iar; /* pc */
568          dst_ts->arch.vex.guest_LR    = ats_new->mst.lr;
569          dst_ts->arch.vex.guest_CTR   = ats_new->mst.ctr;
570          LibVEX_GuestPPC64_put_CR( ats_new->mst.cr, &dst_ts->arch.vex );
571          LibVEX_GuestPPC64_put_XER( ats_new->mst.xer, &dst_ts->arch.vex );
572
573          /* Record what seems like the highest legitimate stack
574             address for this thread, so that the stack unwinder works
575             properly.  It seems reasonable to use the R1 value
576             supplied here. */
577          dst_ts->client_stack_highest_word = dst_ts->arch.vex.guest_GPR1;
578
579          /* The host thread is to start running
580             start_thread_NORETURN */
581          UWord* wrapper_fdescr = (UWord*) & start_thread_NORETURN;
582          ats_new->mst.gpr[1] = (UWord)stack;
583          ats_new->mst.gpr[2] = wrapper_fdescr[1];
584          ats_new->mst.iar    = wrapper_fdescr[0];
585          ats_new->mst.gpr[3] = (UWord)dst_ts;
586
587          /* Set initial cancellation status for the thread. */
588          dst_ts->os_state.cancel_async    = False;
589          dst_ts->os_state.cancel_disabled = False;
590          dst_ts->os_state.cancel_progress = Canc_NoRequest;
591       }
592    }
593 }
594 POST(sys_thread_setstate)
595 {
596    if (ARG3)
597       POST_MEM_WRITE( ARG3, sizeof(struct tstate) );
598    if (0 && VG_(clo_trace_syscalls) && ARG3)
599       ML_(aix5debugstuff_show_tstate)(ARG3, "thread_setstate (OLD)");
600 }
601
602 PRE(sys_FAKE_SIGRETURN)
603 {
604    /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
605       an explanation of what follows. */
606    /* This handles the fake signal-return system call created by
607       sigframe-ppc64-aix5.c. */
608
609    PRINT("FAKE_SIGRETURN ( )");
610
611    vg_assert(VG_(is_valid_tid)(tid));
612    vg_assert(tid >= 1 && tid < VG_N_THREADS);
613    vg_assert(VG_(is_running_thread)(tid));
614
615    /* Remove the signal frame from this thread's (guest) stack,
616       in the process restoring the pre-signal guest state. */
617    VG_(sigframe_destroy)(tid, True);
618
619    /* Tell the driver not to update the guest state with the "result",
620       and set a bogus result to keep it happy. */
621    *flags |= SfNoWriteResult;
622    SET_STATUS_Success(0);
623
624    /* Check to see if any signals arose as a result of this. */
625    *flags |= SfPollAfter;
626 }
627
628
629 /* ---------------------------------------------------------------------
630    The ppc64/AIX5 syscall table
631    ------------------------------------------------------------------ */
632
633 typedef
634    struct {
635       UInt* pSysNo;
636       SyscallTableEntry wrappers;
637    }
638    AIX5SCTabEntry;
639
640 #undef PLAXY
641 #undef PLAX_
642
643 #define PLAXY(sysno, name)                     \
644    { & sysno,                                  \
645      { & WRAPPER_PRE_NAME(ppc64_aix5, name),   \
646        & WRAPPER_POST_NAME(ppc64_aix5, name) }} 
647
648 #define PLAX_(sysno, name)                     \
649    { & sysno,                                  \
650      { & WRAPPER_PRE_NAME(ppc64_aix5, name),   \
651        NULL }} 
652
653 static /* but not const */
654 AIX5SCTabEntry aix5_ppc64_syscall_table[]
655 = {
656     AIXXY(__NR_AIX5___libc_sbrk,        sys___libc_sbrk),
657     AIXX_(__NR_AIX5___msleep,           sys___msleep),
658     PLAXY(__NR_AIX5__clock_gettime,     sys__clock_gettime),
659     AIXX_(__NR_AIX5__exit,              sys__exit),
660     PLAX_(__NR_AIX5__fp_fpscrx64_,      sys__fp_fpscrx64_),
661     AIXX_(__NR_AIX5__getpid,            sys__getpid),
662     AIXXY(__NR_AIX5__nsleep,            sys__nsleep),
663     AIXX_(__NR_AIX5__pause,             sys__pause),
664     AIXXY(__NR_AIX5__poll,              sys__poll),
665     AIXX_(__NR_AIX5__select,            sys__select),
666     AIXX_(__NR_AIX5__sem_wait,          sys__sem_wait),
667     AIXXY(__NR_AIX5__sigaction,         sys__sigaction),
668     AIXX_(__NR_AIX5__thread_self,       sys__thread_self),
669     AIXX_(__NR_AIX5_access,             sys_access),
670     AIXX_(__NR_AIX5_accessx,            sys_accessx),
671     AIXXY(__NR_AIX5_appgetrlimit,       sys_appgetrlimit),
672     AIXXY(__NR_AIX5_appgetrusage,       sys_appgetrusage),
673     AIXX_(__NR_AIX5_appsetrlimit,       sys_appsetrlimit),
674     AIXX_(__NR_AIX5_appulimit,          sys_appulimit),
675     AIXX_(__NR_AIX5_bind,               sys_bind),
676     AIXX_(__NR_AIX5_chdir,              sys_chdir),
677     AIXX_(__NR_AIX5_chmod,              sys_chmod),
678     AIXX_(__NR_AIX5_chown,              sys_chown),
679     AIXX_(__NR_AIX5_close,              sys_close),
680     AIXX_(__NR_AIX5_connext,            sys_connext),
681     AIXX_(__NR_AIX5_execve,             sys_execve),
682     AIXXY(__NR_AIX5_finfo,              sys_finfo),
683     AIXXY(__NR_AIX5_fstatfs,            sys_fstatfs),
684     AIXXY(__NR_AIX5_fstatx,             sys_fstatx),
685     AIXXY(__NR_AIX5_getdirent,          sys_getdirent),
686     AIXXY(__NR_AIX5_getdirent64,        sys_getdirent64),
687     AIXXY(__NR_AIX5_getdomainname,      sys_getdomainname),
688     AIXX_(__NR_AIX5_getgidx,            sys_getgidx),
689     AIXXY(__NR_AIX5_gethostname,        sys_gethostname),
690     AIXXY(__NR_AIX5_getpriv,            sys_getpriv),
691     AIXXY(__NR_AIX5_getprocs,           sys_getprocs),
692     AIXXY(__NR_AIX5_getprocs64,         sys_getprocs), /* XXX: correct? */
693     AIXX_(__NR_AIX5_getrpid,            sys_getrpid),
694     AIXXY(__NR_AIX5_getsockopt,         sys_getsockopt),
695     AIXX_(__NR_AIX5_gettimerid,         sys_gettimerid),
696     AIXX_(__NR_AIX5_getuidx,            sys_getuidx),
697     AIXXY(__NR_AIX5_incinterval,        sys_incinterval),
698     AIXXY(__NR_AIX5_kfcntl,             sys_kfcntl),
699     AIXX_(__NR_AIX5_kfork,              sys_kfork),
700     AIXX_(__NR_AIX5_kill,               sys_kill),
701     AIXXY(__NR_AIX5_kioctl,             sys_kioctl),
702     PLAXY(__NR_AIX5_kload,              sys_kload),
703     AIXX_(__NR_AIX5_klseek,             sys_klseek),
704     AIXXY(__NR_AIX5_kread,              sys_kread),
705     AIXXY(__NR_AIX5_kreadv,             sys_kreadv),
706     AIXX_(__NR_AIX5_kthread_ctl,        sys_kthread_ctl),
707     AIXX_(__NR_AIX5_ktruncate,          sys_ktruncate),
708     PLAXY(__NR_AIX5_kunload64,          sys_kunload64),
709     AIXXY(__NR_AIX5_kwaitpid,           sys_kwaitpid),
710     AIXX_(__NR_AIX5_kwrite,             sys_kwrite),
711     AIXX_(__NR_AIX5_kwritev,            sys_kwritev),
712     AIXX_(__NR_AIX5_lseek,              sys_lseek),
713     AIXX_(__NR_AIX5_mkdir,              sys_mkdir),
714     AIXXY(__NR_AIX5_mmap,               sys_mmap),
715     AIXXY(__NR_AIX5_mntctl,             sys_mntctl),
716     AIXXY(__NR_AIX5_mprotect,           sys_mprotect),
717     AIXXY(__NR_AIX5_munmap,             sys_munmap),
718     AIXXY(__NR_AIX5_ngetpeername,       sys_ngetpeername),
719     AIXXY(__NR_AIX5_ngetsockname,       sys_ngetsockname),
720     AIXXY(__NR_AIX5_nrecvfrom,          sys_nrecvfrom),
721     AIXX_(__NR_AIX5_nrecvmsg,           sys_nrecvmsg),
722     AIXX_(__NR_AIX5_open,               sys_open),
723     AIXXY(__NR_AIX5_pipe,               sys_pipe),
724     AIXX_(__NR_AIX5_privcheck,          sys_privcheck),
725     AIXX_(__NR_AIX5_rename,             sys_rename),
726     AIXXY(__NR_AIX5_sbrk,               sys_sbrk),
727     AIXXY(__NR_AIX5_sem_init,           sys_sem_init),
728     AIXXY(__NR_AIX5_sem_post,           sys_sem_post),
729     AIXX_(__NR_AIX5_send,               sys_send),
730     AIXX_(__NR_AIX5_setgid,             sys_setgid),
731     AIXX_(__NR_AIX5_setsockopt,         sys_setsockopt),
732     AIXX_(__NR_AIX5_setuid,             sys_setuid),
733     AIXXY(__NR_AIX5_shmat,              sys_shmat),
734     AIXXY(__NR_AIX5_shmctl,             sys_shmctl),
735     AIXXY(__NR_AIX5_shmdt,              sys_shmdt),
736     AIXX_(__NR_AIX5_shmget,             sys_shmget),
737     AIXX_(__NR_AIX5_shutdown,           sys_shutdown),
738     AIXX_(__NR_AIX5_sigcleanup,         sys_sigcleanup),
739     AIXXY(__NR_AIX5_sigprocmask,        sys_sigprocmask),
740     AIXXY(__NR_AIX5_sys_parm,           sys_sys_parm),
741     AIXXY(__NR_AIX5_sysconfig,          sys_sysconfig),
742     AIXX_(__NR_AIX5_socket,             sys_socket),
743     AIXXY(__NR_AIX5_statx,              sys_statx),
744     AIXXY(__NR_AIX5_thread_create,      sys_thread_create),
745     AIXX_(__NR_AIX5_thread_init,        sys_thread_init),
746     AIXX_(__NR_AIX5_thread_kill,        sys_thread_kill),
747     AIXXY(__NR_AIX5_thread_setmystate,  sys_thread_setmystate),
748     AIXX_(__NR_AIX5_thread_setmystate_fast, sys_thread_setmystate_fast),
749     PLAXY(__NR_AIX5_thread_setstate,    sys_thread_setstate),
750     AIXX_(__NR_AIX5_thread_terminate_unlock, sys_thread_terminate_unlock),
751     AIXX_(__NR_AIX5_thread_tsleep,      sys_thread_tsleep),
752     AIXX_(__NR_AIX5_thread_twakeup,     sys_thread_twakeup),
753     AIXX_(__NR_AIX5_thread_unlock,      sys_thread_unlock),
754     AIXX_(__NR_AIX5_thread_waitlock_,   sys_thread_waitlock_),
755     AIXXY(__NR_AIX5_times,              sys_times),
756     AIXXY(__NR_AIX5_uname,              sys_uname),
757     AIXX_(__NR_AIX5_unlink,             sys_unlink),
758     AIXX_(__NR_AIX5_utimes,             sys_utimes),
759     AIXXY(__NR_AIX5_vmgetinfo,          sys_vmgetinfo),
760     AIXX_(__NR_AIX5_yield,              sys_yield),
761     PLAX_(__NR_AIX5_FAKE_SIGRETURN,     sys_FAKE_SIGRETURN)
762   };
763
764 SyscallTableEntry* ML_(get_ppc64_aix5_syscall_entry) ( UInt sysno )
765 {
766    Int            i;
767    AIX5SCTabEntry tmp;
768
769    const Int tab_size = sizeof(aix5_ppc64_syscall_table) 
770                         / sizeof(aix5_ppc64_syscall_table[0]);
771
772    for (i = 0; i < tab_size; i++)
773       if (sysno == *(aix5_ppc64_syscall_table[i].pSysNo))
774          break;
775
776    vg_assert(i >= 0 && i <= tab_size);
777    if (i == tab_size)
778       return NULL; /* can't find a wrapper */
779
780    /* Move found one a bit closer to the front, so as to
781       make future searches cheaper. */
782    if (i > 0) {
783       tmp = aix5_ppc64_syscall_table[i-1];
784       aix5_ppc64_syscall_table[i-1] = aix5_ppc64_syscall_table[i];
785       aix5_ppc64_syscall_table[i] = tmp;
786       i--;
787    }
788
789    vg_assert(i >= 0 && i < tab_size);
790    return &aix5_ppc64_syscall_table[i].wrappers;
791 }
792
793 #endif // defined(VGP_ppc64_aix5)
794
795 /*--------------------------------------------------------------------*/
796 /*--- end                                                          ---*/
797 /*--------------------------------------------------------------------*/