• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*--------------------------------------------------------------------*/
3 /*--- Types and macros for writing syscall wrappers.               ---*/
4 /*---                                        priv_types_n_macros.h ---*/
5 /*--------------------------------------------------------------------*/
6 
7 /*
8    This file is part of Valgrind, a dynamic binary instrumentation
9    framework.
10 
11    Copyright (C) 2000-2010 Julian Seward
12       jseward@acm.org
13 
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License as
16    published by the Free Software Foundation; either version 2 of the
17    License, or (at your option) any later version.
18 
19    This program is distributed in the hope that it will be useful, but
20    WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22    General Public License for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27    02111-1307, USA.
28 
29    The GNU General Public License is contained in the file COPYING.
30 */
31 
32 #ifndef __PRIV_TYPES_N_MACROS_H
33 #define __PRIV_TYPES_N_MACROS_H
34 
35 /* requires #include "pub_core_options.h" */
36 /* requires #include "pub_core_signals.h" */
37 
38 /* This header defines types and macros which are useful for writing
39    syscall wrappers.  It does not give prototypes for any such
40    headers, though: that is the job of the priv_syswrap-*.h headers.
41    This header gets included in any file which defines or declares
42    wrappers, and as such should only contain stuff which is relevant
43    to all such files.
44 */
45 
46 /* ---------------------------------------------------------------------
47    Types that are used in syscall wrappers.
48    ------------------------------------------------------------------ */
49 
50 /* Arguments for a syscall. */
51 typedef
52    struct SyscallArgs {
53       Word sysno;
54       UWord arg1;
55       UWord arg2;
56       UWord arg3;
57       UWord arg4;
58       UWord arg5;
59       UWord arg6;
60       UWord arg7;
61       UWord arg8;
62    }
63    SyscallArgs;
64 
65 /* Current status of a syscall being done on behalf of the client. */
66 typedef
67    struct SyscallStatus {
68       enum {
69          /* call is complete, result is in 'res' */
70          SsComplete=1,
71          /* syscall not yet completed; must be handed to the kernel */
72          SsHandToKernel,
73          /* not currently handling a syscall for this thread */
74          SsIdle
75       } what;
76       SysRes sres; /* only meaningful for .what == SsComplete */
77    }
78    SyscallStatus;
79 
80 /* Guest state layout info for syscall args. */
81 typedef
82    struct {
83       // Note that, depending on the platform, arguments may be found in
84       // registers or on the stack.  (See the comment at the top of
85       // syswrap-main.c for per-platform details.)  For register arguments
86       // (which have o_arg field names) the o_arg value is the offset into
87       // the vex register state.  For stack arguments (which have s_arg
88       // field names), the s_arg value is the offset from the stack pointer.
89       Int o_sysno;
90 #     if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
91          || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) \
92          || defined(VGP_arm_linux)
93       Int o_arg1;
94       Int o_arg2;
95       Int o_arg3;
96       Int o_arg4;
97       Int o_arg5;
98       Int o_arg6;
99       Int uu_arg7;
100       Int uu_arg8;
101 #     elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
102       Int o_arg1;
103       Int o_arg2;
104       Int o_arg3;
105       Int o_arg4;
106       Int o_arg5;
107       Int o_arg6;
108       Int o_arg7;
109       Int o_arg8;
110 #     elif defined(VGP_x86_darwin)
111       Int s_arg1;
112       Int s_arg2;
113       Int s_arg3;
114       Int s_arg4;
115       Int s_arg5;
116       Int s_arg6;
117       Int s_arg7;
118       Int s_arg8;
119 #     elif defined(VGP_amd64_darwin)
120       Int o_arg1;
121       Int o_arg2;
122       Int o_arg3;
123       Int o_arg4;
124       Int o_arg5;
125       Int o_arg6;
126       Int s_arg7;
127       Int s_arg8;
128 #     else
129 #       error "Unknown platform"
130 #     endif
131    }
132    SyscallArgLayout;
133 
134 /* Flags describing syscall wrappers */
135 #define SfMayBlock      (1 << 1) /* may block                         */
136 #define SfPostOnFail    (1 << 2) /* call POST() function on failure   */
137 #define SfPollAfter     (1 << 3) /* poll for signals on completion    */
138 #define SfYieldAfter    (1 << 4) /* yield on completion               */
139 #define SfNoWriteResult (1 << 5) /* don't write result to guest state */
140 
141 
142 /* ---------------------------------------------------------------------
143    The syscall table.
144    ------------------------------------------------------------------ */
145 
146 typedef
147    struct {
148       void (*before) ( ThreadId,
149                        SyscallArgLayout*,
150                        /*MOD*/SyscallArgs*,
151                        /*OUT*/SyscallStatus*,
152                        /*OUT*/UWord*
153                      );
154 
155       void (*after)  ( ThreadId,
156                        SyscallArgs*,
157                        SyscallStatus*
158                      );
159    }
160    SyscallTableEntry;
161 
162 /* Syscall table entries bind __NR_xxx syscall numbers to the PRE/POST
163    wrappers for the relevant syscall used in the OS kernel for that
164    number.  Note that the constant names don't always match the
165    wrapper names in a straightforward way.  For example, on x86/Linux:
166 
167       __NR_lchown       --> sys_lchown16()
168       __NR_lchown32     --> sys_lchown()
169       __NR_select       --> old_select()
170       __NR__newselect   --> sys_select()
171 */
172 
173 
174 /* A function to find the syscall table entry for a given sysno.  If
175    none is found, return NULL.  This used to be done with a single
176    fixed sized table exposed to the caller, but that's too inflexible;
177    hence now use a function which can do arbitrary messing around to
178    find the required entry. */
179 #if defined(VGO_linux)
180 extern
181 SyscallTableEntry* ML_(get_linux_syscall_entry)( UInt sysno );
182 
183 #elif defined(VGP_ppc32_aix5)
184 /* Same scheme on AIX5.  This is more complex than the simple fixed
185    table lookup typical for Linux, since the syscalls don't have fixed
186    numbers. */
187 extern
188 SyscallTableEntry* ML_(get_ppc32_aix5_syscall_entry) ( UInt sysno );
189 
190 #elif defined(VGP_ppc64_aix5)
191 extern
192 SyscallTableEntry* ML_(get_ppc64_aix5_syscall_entry) ( UInt sysno );
193 
194 #elif defined(VGO_darwin)
195 /* XXX: Darwin still uses the old scheme of exposing the table
196    array(s) and size(s) directly to syswrap-main.c.  This should be
197    fixed. */
198 
199 extern const SyscallTableEntry ML_(syscall_table)[];
200 extern const UInt ML_(syscall_table_size);
201 
202 #else
203 #  error Unknown OS
204 #endif
205 
206 /* ---------------------------------------------------------------------
207    Declaring and defining wrappers.
208    ------------------------------------------------------------------ */
209 
210 /* Templates for generating the PRE and POST macros -- that is, the
211    formal parameter lists for the definitions of wrapper functions.
212 
213    Since these names exist in the global namespace, 'auxstr' should
214    give an auxiliary string, eg, "generic", "x86_linux", "linux", etc,
215    that ensures the names won't clash with other wrappers.
216 
217    You should create corresponding global declarations using
218    DECL_TEMPLATE (indirectly) below.
219 
220    Note.  The silly name "arrghs" is used rather than just "args"
221    because a few wrappers declare the name "args" themselves, and
222    renaming those decls can change the name that comes out in error
223    messages (on scalar arg checks).  Hence rename this instead.
224 */
225 
226 #define DEFN_PRE_TEMPLATE(auxstr, name)                          \
227    void vgSysWrap_##auxstr##_##name##_before                     \
228                                  ( ThreadId tid,                 \
229                                    SyscallArgLayout* layout,     \
230                                    /*MOD*/SyscallArgs* arrghs,   \
231                                    /*OUT*/SyscallStatus* status, \
232                                    /*OUT*/UWord* flags           \
233                                  )
234 
235 #define DEFN_POST_TEMPLATE(auxstr, name)                         \
236    void vgSysWrap_##auxstr##_##name##_after                      \
237                                  ( ThreadId tid,                 \
238                                    SyscallArgs* arrghs,          \
239                                    SyscallStatus* status         \
240                                  )
241 
242 
243 /* This macro generates declarations (prototypes) for wrappers.  It
244    declares both the pre-wrapper and the post-wrapper, even though the
245    post-wrapper may not actually exist.
246 */
247 #define DECL_TEMPLATE(auxstr, name)                              \
248    extern                                                        \
249    void vgSysWrap_##auxstr##_##name##_before                     \
250                                  ( ThreadId tid,                 \
251                                    SyscallArgLayout* layout,     \
252                                    /*MOD*/SyscallArgs* arrghs,   \
253                                    /*OUT*/SyscallStatus* status, \
254                                    /*OUT*/UWord* flags           \
255                                  );                              \
256    extern                                                        \
257    void vgSysWrap_##auxstr##_##name##_after                      \
258                                  ( ThreadId tid,                 \
259                                    SyscallArgs* arrghs,          \
260                                    SyscallStatus* status         \
261                                  );
262 
263 
264 
265 /* Macros for conveniently generating entries in the syscall
266    tables.  This first pair are not used directly. */
267 
268 #define WRAPPER_ENTRY_X_(auxstr, sysno, name) \
269    [sysno] = { vgSysWrap_##auxstr##_##name##_before, NULL }
270 #define WRAPPER_ENTRY_XY(auxstr, sysno, name) \
271    [sysno] = { vgSysWrap_##auxstr##_##name##_before, \
272                vgSysWrap_##auxstr##_##name##_after }
273 
274 #define WRAPPER_PRE_NAME(auxstr, name) \
275     vgSysWrap_##auxstr##_##name##_before
276 #define WRAPPER_POST_NAME(auxstr, name) \
277     vgSysWrap_##auxstr##_##name##_after
278 
279 /* Add a generic wrapper to a syscall table. */
280 #if defined(VGO_linux) || defined(VGO_aix5)
281 #  define GENX_(sysno, name)  WRAPPER_ENTRY_X_(generic, sysno, name)
282 #  define GENXY(sysno, name)  WRAPPER_ENTRY_XY(generic, sysno, name)
283 #elif defined(VGO_darwin)
284 #  define GENX_(sysno, name)  WRAPPER_ENTRY_X_(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
285 #  define GENXY(sysno, name)  WRAPPER_ENTRY_XY(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
286 #else
287 #  error Unknown OS
288 #endif
289 
290 /* Add a Linux-specific, arch-independent wrapper to a syscall
291    table. */
292 #define LINX_(sysno, name)    WRAPPER_ENTRY_X_(linux, sysno, name)
293 #define LINXY(sysno, name)    WRAPPER_ENTRY_XY(linux, sysno, name)
294 
295 /* Add an AIX5-specific, arch-independent wrapper to a syscall
296    table. */
297 #define AIXXY(sysno, name)                     \
298    { & sysno,                                  \
299      { & WRAPPER_PRE_NAME(aix5, name),         \
300        & WRAPPER_POST_NAME(aix5, name) }}
301 
302 #define AIXX_(sysno, name)                     \
303    { & sysno,                                  \
304      { & WRAPPER_PRE_NAME(aix5, name),         \
305        NULL }}
306 
307 
308 /* ---------------------------------------------------------------------
309    Macros useful for writing wrappers concisely.  These refer to the
310    parameters declared by DEFN_{PRE,POST}_TEMPLATE and so in a way do
311    not help clarity of understanding.  But they are just too useful to
312    omit.
313    ------------------------------------------------------------------ */
314 
315 /* Reference to the syscall's arguments -- the ones which the
316    pre-wrapper may have modified, not the original copy. */
317 #define SYSNO  (arrghs->sysno)
318 #define ARG1   (arrghs->arg1)
319 #define ARG2   (arrghs->arg2)
320 #define ARG3   (arrghs->arg3)
321 #define ARG4   (arrghs->arg4)
322 #define ARG5   (arrghs->arg5)
323 #define ARG6   (arrghs->arg6)
324 #define ARG7   (arrghs->arg7)
325 #define ARG8   (arrghs->arg8)
326 
327 /* Reference to the syscall's current result status/value.  General
328    paranoia all round. */
329 #define SUCCESS       (status->what == SsComplete && !sr_isError(status->sres))
330 #define FAILURE       (status->what == SsComplete &&  sr_isError(status->sres))
331 #define SWHAT         (status->what)
332 #define RES           (getRES(status))
333 #define RESHI         (getRESHI(status))
334 #define ERR           (getERR(status))
335 
getRES(SyscallStatus * st)336 static inline UWord getRES ( SyscallStatus* st ) {
337    vg_assert(st->what == SsComplete);
338    vg_assert(!sr_isError(st->sres));
339    return sr_Res(st->sres);
340 }
341 
getRESHI(SyscallStatus * st)342 static inline UWord getRESHI ( SyscallStatus* st ) {
343    vg_assert(st->what == SsComplete);
344    vg_assert(!sr_isError(st->sres));
345    return sr_ResHI(st->sres);
346 }
347 
getERR(SyscallStatus * st)348 static inline UWord getERR ( SyscallStatus* st ) {
349    vg_assert(st->what == SsComplete);
350    vg_assert(sr_isError(st->sres));
351    return sr_Err(st->sres);
352 }
353 
354 
355 /* Set the current result status/value in various ways. */
356 #define SET_STATUS_Success(zzz)                      \
357    do { status->what = SsComplete;                   \
358         status->sres = VG_(mk_SysRes_Success)(zzz);  \
359    } while (0)
360 
361 #define SET_STATUS_Failure(zzz)                      \
362    do { Word wzz = (Word)(zzz);                      \
363         /* Catch out wildly bogus error values. */   \
364         vg_assert(wzz >= 0 && wzz < 10000);          \
365         status->what = SsComplete;                   \
366         status->sres = VG_(mk_SysRes_Error)(wzz);    \
367    } while (0)
368 
369 #define SET_STATUS_from_SysRes(zzz)                  \
370    do {                                              \
371      status->what = SsComplete;                      \
372      status->sres = (zzz);                           \
373    } while (0)
374 
375 
376 #define PRINT(format, args...)                       \
377    if (VG_(clo_trace_syscalls))                      \
378       VG_(printf)(format, ## args)
379 
380 
381 
382 /* Macros used to tell tools about uses of scalar arguments.  Note,
383    these assume little-endianness.  These can only be used in
384    pre-wrappers, and they refer to the layout parameter passed in. */
385 /* PRRSN == "pre-register-read-sysno"
386    PRRAn == "pre-register-read-argument"
387    PSRAn == "pre-stack-read-argument"
388    PRAn  == "pre-read-argument"
389 */
390 
391 #if defined(VGO_linux)
392    /* Up to 6 parameters, all in registers. */
393 #  define PRA1(s,t,a) PRRAn(1,s,t,a)
394 #  define PRA2(s,t,a) PRRAn(2,s,t,a)
395 #  define PRA3(s,t,a) PRRAn(3,s,t,a)
396 #  define PRA4(s,t,a) PRRAn(4,s,t,a)
397 #  define PRA5(s,t,a) PRRAn(5,s,t,a)
398 #  define PRA6(s,t,a) PRRAn(6,s,t,a)
399 
400 #elif defined(VGO_aix5)
401 #  error Need to fill this in for AIX5
402 
403 #elif defined(VGP_x86_darwin)
404    /* Up to 8 parameters, all on the stack. */
405 #  define PRA1(s,t,a) PSRAn(1,s,t,a)
406 #  define PRA2(s,t,a) PSRAn(2,s,t,a)
407 #  define PRA3(s,t,a) PSRAn(3,s,t,a)
408 #  define PRA4(s,t,a) PSRAn(4,s,t,a)
409 #  define PRA5(s,t,a) PSRAn(5,s,t,a)
410 #  define PRA6(s,t,a) PSRAn(6,s,t,a)
411 #  define PRA7(s,t,a) PSRAn(7,s,t,a)
412 #  define PRA8(s,t,a) PSRAn(8,s,t,a)
413 
414 #elif defined(VGP_amd64_darwin)
415    /* Up to 8 parameters, 6 in registers, 2 on the stack. */
416 #  define PRA1(s,t,a) PRRAn(1,s,t,a)
417 #  define PRA2(s,t,a) PRRAn(2,s,t,a)
418 #  define PRA3(s,t,a) PRRAn(3,s,t,a)
419 #  define PRA4(s,t,a) PRRAn(4,s,t,a)
420 #  define PRA5(s,t,a) PRRAn(5,s,t,a)
421 #  define PRA6(s,t,a) PRRAn(6,s,t,a)
422 #  define PRA7(s,t,a) PSRAn(7,s,t,a)
423 #  define PRA8(s,t,a) PSRAn(8,s,t,a)
424 
425 #else
426 #  error Unknown platform
427 #endif
428 
429 
430 /* Tell the tool that the syscall number is being read. */
431 #define PRRSN \
432       VG_(tdict).track_pre_reg_read(Vg_CoreSysCall, tid, "(syscallno)", \
433                                     layout->o_sysno, sizeof(UWord));
434 
435 /* REGISTER PARAMETERS */
436 
437 /* PRRAn: Tell the tool that the register holding the n-th syscall
438    argument is being read, at type 't' which must be at most the size
439    of a register but can be smaller.  In the latter case we need to be
440    careful about endianness. */
441 
442 /* little-endian: the part of the guest state being read is
443       let here = offset_of_reg
444       in  [here .. here + sizeof(t) - 1]
445    since the least significant parts of the guest register are stored
446    in memory at the lowest address.
447 */
448 #define PRRAn_LE(n,s,t,a)                          \
449    do {                                            \
450       Int here = layout->o_arg##n;                 \
451       vg_assert(sizeof(t) <= sizeof(UWord));       \
452       vg_assert(here >= 0);                        \
453       VG_(tdict).track_pre_reg_read(               \
454          Vg_CoreSysCall, tid, s"("#a")",           \
455          here, sizeof(t)                           \
456       );                                           \
457    } while (0)
458 
459 /* big-endian: the part of the guest state being read is
460       let next = offset_of_reg + sizeof(reg)
461       in  [next - sizeof(t) .. next - 1]
462    since the least significant parts of the guest register are stored
463    in memory at the highest address.
464 */
465 #define PRRAn_BE(n,s,t,a)                          \
466    do {                                            \
467       Int here = layout->o_arg##n;                 \
468       Int next = layout->o_arg##n + sizeof(UWord); \
469       vg_assert(sizeof(t) <= sizeof(UWord));       \
470       vg_assert(here >= 0);                        \
471       VG_(tdict).track_pre_reg_read(               \
472          Vg_CoreSysCall, tid, s"("#a")",           \
473          next-sizeof(t), sizeof(t)                 \
474       );                                           \
475    } while (0)
476 
477 #if defined(VG_BIGENDIAN)
478 #  define PRRAn(n,s,t,a) PRRAn_BE(n,s,t,a)
479 #elif defined(VG_LITTLEENDIAN)
480 #  define PRRAn(n,s,t,a) PRRAn_LE(n,s,t,a)
481 #else
482 #  error "Unknown endianness"
483 #endif
484 
485 
486 /* STACK PARAMETERS */
487 
488 /* PSRAn: Tell the tool that the memory holding the n-th syscall
489    argument is being read, at type 't' which must be at most the size
490    of a register but can be smaller.  In the latter case we need to be
491    careful about endianness. */
492 
493 /* little-endian: the part of the guest state being read is
494       let here = offset_of_reg
495       in  [here .. here + sizeof(t) - 1]
496    since the least significant parts of the guest register are stored
497    in memory at the lowest address.
498 */
499 #define PSRAn_LE(n,s,t,a)                          \
500    do {                                            \
501       Addr here = layout->s_arg##n + VG_(get_SP)(tid); \
502       vg_assert(sizeof(t) <= sizeof(UWord));       \
503       VG_(tdict).track_pre_mem_read(               \
504          Vg_CoreSysCallArgInMem, tid, s"("#a")",   \
505          here, sizeof(t)                           \
506       );                                           \
507    } while (0)
508 
509 /* big-endian: the part of the guest state being read is
510       let next = offset_of_reg + sizeof(reg)
511       in  [next - sizeof(t) .. next - 1]
512    since the least significant parts of the guest register are stored
513    in memory at the highest address.
514 */
515 #define PSRAn_BE(n,s,t,a)                                         \
516    do {                                                           \
517       Addr next = layout->o_arg##n + sizeof(UWord) +              \
518                   VG_(threads)[tid].arch.vex.VG_STACK_PTR;        \
519       vg_assert(sizeof(t) <= sizeof(UWord));                      \
520       VG_(tdict).track_pre_mem_read(                              \
521          Vg_CoreSysCallArgInMem, tid, s"("#a")",                  \
522          next-sizeof(t), sizeof(t)                                \
523       );                                                          \
524    } while (0)
525 
526 #if defined(VG_BIGENDIAN)
527 #  define PSRAn(n,s,t,a) PSRAn_BE(n,s,t,a)
528 #elif defined(VG_LITTLEENDIAN)
529 #  define PSRAn(n,s,t,a) PSRAn_LE(n,s,t,a)
530 #else
531 #  error "Unknown endianness"
532 #endif
533 
534 
535 #define PRE_REG_READ0(tr, s) \
536    if (VG_(tdict).track_pre_reg_read) { \
537       PRRSN; \
538    }
539 #define PRE_REG_READ1(tr, s, t1, a1) \
540    if (VG_(tdict).track_pre_reg_read) { \
541       PRRSN; \
542       PRA1(s,t1,a1);                            \
543    }
544 #define PRE_REG_READ2(tr, s, t1, a1, t2, a2) \
545    if (VG_(tdict).track_pre_reg_read) { \
546       PRRSN; \
547       PRA1(s,t1,a1); PRA2(s,t2,a2);           \
548    }
549 #define PRE_REG_READ3(tr, s, t1, a1, t2, a2, t3, a3) \
550    if (VG_(tdict).track_pre_reg_read) { \
551       PRRSN; \
552       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
553    }
554 #define PRE_REG_READ4(tr, s, t1, a1, t2, a2, t3, a3, t4, a4) \
555    if (VG_(tdict).track_pre_reg_read) { \
556       PRRSN; \
557       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
558       PRA4(s,t4,a4);                                    \
559    }
560 #define PRE_REG_READ5(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \
561    if (VG_(tdict).track_pre_reg_read) { \
562       PRRSN; \
563       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
564       PRA4(s,t4,a4); PRA5(s,t5,a5);                   \
565    }
566 #define PRE_REG_READ6(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6) \
567    if (VG_(tdict).track_pre_reg_read) { \
568       PRRSN; \
569       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
570       PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
571    }
572 #define PRE_REG_READ7(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7) \
573    if (VG_(tdict).track_pre_reg_read) { \
574       PRRSN; \
575       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
576       PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
577       PRA7(s,t7,a7);                                     \
578    }
579 
580 #define PRE_REG_READ8(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7, t8, a8) \
581    if (VG_(tdict).track_pre_reg_read) { \
582       PRRSN; \
583       PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
584       PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
585       PRA7(s,t7,a7); PRA8(s,t8,a8);                    \
586    }
587 
588 #define PRE_MEM_READ(zzname, zzaddr, zzlen) \
589    VG_TRACK( pre_mem_read, Vg_CoreSysCall, tid, zzname, zzaddr, zzlen)
590 
591 #define PRE_MEM_RASCIIZ(zzname, zzaddr) \
592    VG_TRACK( pre_mem_read_asciiz, Vg_CoreSysCall, tid, zzname, zzaddr)
593 
594 #define PRE_MEM_WRITE(zzname, zzaddr, zzlen) \
595    VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid, zzname, zzaddr, zzlen)
596 
597 #define POST_MEM_WRITE(zzaddr, zzlen) \
598    VG_TRACK( post_mem_write, Vg_CoreSysCall, tid, zzaddr, zzlen)
599 
600 
601 #define PRE_FIELD_READ(zzname, zzfield) \
602     PRE_MEM_READ(zzname, (UWord)&zzfield, sizeof(zzfield))
603 
604 #define PRE_FIELD_WRITE(zzname, zzfield) \
605     PRE_MEM_WRITE(zzname, (UWord)&zzfield, sizeof(zzfield))
606 
607 #define POST_FIELD_WRITE(zzfield) \
608     POST_MEM_WRITE((UWord)&zzfield, sizeof(zzfield))
609 
610 
611 #endif   // __PRIV_TYPES_N_MACROS_H
612 
613 /*--------------------------------------------------------------------*/
614 /*--- end                                                          ---*/
615 /*--------------------------------------------------------------------*/
616