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