tests/vg_regtest: Always evaluate prerequisite expressions with sh
[valgrind.git] / coregrind / m_addrinfo.c
blob5ff0d28960277f6f8e56c8138355d290a41f38e5
2 /*--------------------------------------------------------------------*/
3 /*--- Obtaining information about an address. ---*/
4 /*--- m_addrinfo.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2008-2013 OpenWorks Ltd
12 info@open-works.co.uk
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.
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.
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.
29 The GNU General Public License is contained in the file COPYING.
32 #include "pub_core_basics.h"
33 #include "pub_core_clientstate.h"
34 #include "pub_core_libcassert.h"
35 #include "pub_core_libcbase.h"
36 #include "pub_core_libcprint.h"
37 #include "pub_core_xarray.h"
38 #include "pub_core_debuginfo.h"
39 #include "pub_core_execontext.h"
40 #include "pub_core_addrinfo.h"
41 #include "pub_core_mallocfree.h"
42 #include "pub_core_machine.h"
43 #include "pub_core_options.h"
44 #include "pub_core_threadstate.h"
45 #include "pub_core_stacktrace.h"
46 #include "pub_core_stacks.h"
47 #include "pub_core_aspacemgr.h"
49 /* Returns the tid whose stack includes the address a.
50 If not found, returns VG_INVALID_THREADID. */
51 static ThreadId find_tid_with_stack_containing (Addr a)
53 ThreadId tid;
54 Addr start, end;
56 start = 0;
57 end = 0;
58 VG_(stack_limits)(a, &start, &end);
59 if (start == end) {
60 // No stack found
61 vg_assert (start == 0 && end == 0);
62 return VG_INVALID_THREADID;
65 /* Stack limits found. Search the tid to which this stack belongs. */
66 vg_assert (start <= a);
67 vg_assert (a <= end);
69 /* The stack end (highest accessible byte) is for sure inside the 'active'
70 part of the stack of the searched tid.
71 So, scan all 'active' stacks with VG_(thread_stack_reset_iter) ... */
73 Addr stack_min, stack_max;
75 VG_(thread_stack_reset_iter)(&tid);
76 while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
77 if (stack_min <= end && end <= stack_max)
78 return tid;
82 /* We can arrive here if a stack was registered with wrong bounds
83 (e.g. end above the highest addressable byte)
84 and/or if the thread for the registered stack is dead, but
85 the stack was not unregistered. */
86 return VG_INVALID_THREADID;
89 void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
91 VgSectKind sect;
93 /* -- Perhaps the variable type/location data describes it? -- */
94 ai->Addr.Variable.descr1
95 = VG_(newXA)( VG_(malloc), "mc.da.descr1",
96 VG_(free), sizeof(HChar) );
97 ai->Addr.Variable.descr2
98 = VG_(newXA)( VG_(malloc), "mc.da.descr2",
99 VG_(free), sizeof(HChar) );
101 (void) VG_(get_data_description)( ai->Addr.Variable.descr1,
102 ai->Addr.Variable.descr2, a );
103 /* If there's nothing in descr1/2, free them. Why is it safe to
104 VG_(indexXA) at zero here? Because VG_(get_data_description)
105 guarantees to zero terminate descr1/2 regardless of the outcome
106 of the call. So there's always at least one element in each XA
107 after the call.
109 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr1, 0 ))) {
110 VG_(deleteXA)( ai->Addr.Variable.descr1 );
111 ai->Addr.Variable.descr1 = NULL;
113 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
114 VG_(deleteXA)( ai->Addr.Variable.descr2 );
115 ai->Addr.Variable.descr2 = NULL;
117 /* Assume (assert) that VG_(get_data_description) fills in descr1
118 before it fills in descr2 */
119 if (ai->Addr.Variable.descr1 == NULL)
120 vg_assert(ai->Addr.Variable.descr2 == NULL);
121 /* So did we get lucky? */
122 if (ai->Addr.Variable.descr1 != NULL) {
123 ai->tag = Addr_Variable;
124 return;
126 /* -- Have a look at the low level data symbols - perhaps it's in
127 there. -- */
128 const HChar *name;
129 if (VG_(get_datasym_and_offset)(
130 a, &name,
131 &ai->Addr.DataSym.offset )) {
132 ai->Addr.DataSym.name = VG_(strdup)("mc.da.dsname", name);
133 ai->tag = Addr_DataSym;
134 return;
136 /* -- Perhaps it's on a thread's stack? -- */
138 ThreadId tid;
139 Addr stack_min, stack_max;
140 VG_(thread_stack_reset_iter)(&tid);
141 while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
142 if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
143 Addr ips[VG_(clo_backtrace_size)],
144 sps[VG_(clo_backtrace_size)];
145 UInt n_frames;
146 UInt f;
148 ai->tag = Addr_Stack;
149 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
150 ai->Addr.Stack.tinfo.tid = tid;
151 ai->Addr.Stack.IP = 0;
152 ai->Addr.Stack.frameNo = -1;
153 ai->Addr.Stack.stackPos = StackPos_stacked;
154 ai->Addr.Stack.spoffset = 0; // Unused.
155 /* It is on thread tid stack. Build a stacktrace, and
156 find the frame sp[f] .. sp[f+1] where the address is.
157 Store the found frameNo and the corresponding IP in
158 the description.
159 When description is printed, IP will be translated to
160 the function name containing IP.
161 Before accepting to describe addr with sp[f] .. sp[f+1],
162 we verify the sp looks sane: reasonably sized frame,
163 inside the stack.
164 We could check the ABI required alignment for sp (what is it?)
165 is respected, except for the innermost stack pointer ? */
166 n_frames = VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size),
167 sps, NULL, 0/*first_ip_delta*/ );
168 for (f = 0; f < n_frames-1; f++) {
169 if (sps[f] <= a && a < sps[f+1]
170 && sps[f+1] - sps[f] <= 0x4000000 // 64 MB, arbitrary
171 && sps[f+1] <= stack_max
172 && sps[f] >= stack_min - VG_STACK_REDZONE_SZB) {
173 ai->Addr.Stack.frameNo = f;
174 ai->Addr.Stack.IP = ips[f];
175 break;
178 return;
183 /* -- Maybe it is in one of the m_mallocfree.c arenas. -- */
185 AddrArenaInfo aai;
186 VG_(describe_arena_addr) ( a, &aai );
187 if (aai.name != NULL) {
188 ai->tag = Addr_Block;
189 if (aai.aid == VG_AR_CLIENT)
190 ai->Addr.Block.block_kind
191 = aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd;
192 else
193 ai->Addr.Block.block_kind
194 = aai.free
195 ? Block_ValgrindArenaFree : Block_ValgrindArenaMallocd;
196 ai->Addr.Block.block_desc = aai.name;
197 ai->Addr.Block.block_szB = aai.block_szB;
198 ai->Addr.Block.rwoffset = aai.rwoffset;
199 ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
200 VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
201 ai->Addr.Block.freed_at = VG_(null_ExeContext)();
202 return;
206 /* -- last ditch attempt at classification -- */
207 sect = VG_(DebugInfo_sect_kind)( &name, a);
208 if (sect != Vg_SectUnknown) {
209 ai->tag = Addr_SectKind;
210 ai->Addr.SectKind.objname = VG_(strdup)("mc.da.dsname", name);
211 ai->Addr.SectKind.kind = sect;
212 return;
215 /* -- and yet another last ditch attempt at classification -- */
216 /* If the address is in a stack between the stack bottom (highest byte)
217 and the current stack ptr, it will have been already described above.
218 But maybe it is in a stack, but below the stack ptr (typical
219 for a 'use after return' or in the stack guard page (thread stack
220 too small). */
222 ThreadId tid;
223 StackPos stackPos = StackPos_stacked;
224 // Default init to StackPos_stacked, to silence gcc warning.
225 // We assert this value is overriden if a stack descr is produced.
227 // First try to find a tid with stack containing a
228 tid = find_tid_with_stack_containing (a);
229 if (tid != VG_INVALID_THREADID) {
230 /* Should be below stack pointer, as if it is >= SP, it
231 will have been described as StackPos_stacked above. */
232 stackPos = StackPos_below_stack_ptr;
233 } else {
234 /* Try to find a stack with guard page containing a.
235 For this, check if a is in a page mapped without r, w and x. */
236 const NSegment *seg = VG_(am_find_nsegment) (a);
237 if (seg != NULL && seg->kind == SkAnonC
238 && !seg->hasR && !seg->hasW && !seg->hasX) {
239 /* This looks a plausible guard page. Check if a is close to
240 the start of stack (lowest byte). */
241 tid = find_tid_with_stack_containing (VG_PGROUNDUP(a+1));
242 if (tid != VG_INVALID_THREADID)
243 stackPos = StackPos_guard_page;
247 if (tid != VG_INVALID_THREADID) {
248 ai->tag = Addr_Stack;
249 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
250 ai->Addr.Stack.tinfo.tid = tid;
251 ai->Addr.Stack.IP = 0;
252 ai->Addr.Stack.frameNo = -1;
253 vg_assert (stackPos != StackPos_stacked);
254 ai->Addr.Stack.stackPos = stackPos;
255 vg_assert (a < VG_(get_SP)(tid));
256 ai->Addr.Stack.spoffset = a - VG_(get_SP)(tid);
257 return;
261 /* -- and yet another last ditch attempt at classification -- */
262 /* Try to find a segment belonging to the client. */
264 const NSegment *seg = VG_(am_find_nsegment) (a);
266 /* Special case to detect the brk data segment. */
267 if (seg != NULL
268 #if defined(VGO_solaris)
269 && (seg->kind == SkAnonC || seg->kind == SkFileC)
270 #else
271 && seg->kind == SkAnonC
272 #endif /* VGO_solaris */
273 && VG_(brk_limit) >= seg->start
274 && VG_(brk_limit) <= seg->end+1) {
275 /* Address a is in a Anon Client segment which contains
276 VG_(brk_limit). So, this segment is the brk data segment
277 as initimg-linux.c:setup_client_dataseg maps an anonymous
278 segment followed by a reservation, with one reservation
279 page that will never be used by syswrap-generic.c:do_brk,
280 when increasing VG_(brk_limit).
281 So, the brk data segment will never be merged with the
282 next segment, and so an address in that area will
283 either be in the brk data segment, or in the unmapped
284 part of the brk data segment reservation. */
285 ai->tag = Addr_BrkSegment;
286 ai->Addr.BrkSegment.brk_limit = VG_(brk_limit);
287 return;
290 if (seg != NULL
291 && (seg->kind == SkAnonC
292 || seg->kind == SkFileC
293 || seg->kind == SkShmC)) {
294 ai->tag = Addr_SegmentKind;
295 ai->Addr.SegmentKind.segkind = seg->kind;
296 ai->Addr.SegmentKind.filename = NULL;
297 if (seg->kind == SkFileC)
298 ai->Addr.SegmentKind.filename
299 = VG_(strdup)("mc.da.skfname", VG_(am_get_filename)(seg));
300 ai->Addr.SegmentKind.hasR = seg->hasR;
301 ai->Addr.SegmentKind.hasW = seg->hasW;
302 ai->Addr.SegmentKind.hasX = seg->hasX;
303 return;
307 /* -- Clueless ... -- */
308 ai->tag = Addr_Unknown;
309 return;
312 void VG_(initThreadInfo) (ThreadInfo *tinfo)
314 tinfo->tid = 0;
315 tinfo->tnr = 0;
318 void VG_(clear_addrinfo) ( AddrInfo* ai)
320 switch (ai->tag) {
321 case Addr_Undescribed:
322 break;
324 case Addr_Unknown:
325 break;
327 case Addr_Stack:
328 break;
330 case Addr_Block:
331 break;
333 case Addr_DataSym:
334 VG_(free)(ai->Addr.DataSym.name);
335 break;
337 case Addr_Variable:
338 if (ai->Addr.Variable.descr1 != NULL) {
339 VG_(deleteXA)( ai->Addr.Variable.descr1 );
340 ai->Addr.Variable.descr1 = NULL;
342 if (ai->Addr.Variable.descr2 != NULL) {
343 VG_(deleteXA)( ai->Addr.Variable.descr2 );
344 ai->Addr.Variable.descr2 = NULL;
346 break;
348 case Addr_SectKind:
349 VG_(free)(ai->Addr.SectKind.objname);
350 break;
352 case Addr_BrkSegment:
353 break;
355 case Addr_SegmentKind:
356 VG_(free)(ai->Addr.SegmentKind.filename);
357 break;
359 default:
360 VG_(core_panic)("VG_(clear_addrinfo)");
363 ai->tag = Addr_Undescribed;
366 static Bool is_arena_BlockKind(BlockKind bk)
368 switch (bk) {
369 case Block_Mallocd:
370 case Block_Freed:
371 case Block_MempoolChunk:
372 case Block_UserG: return False;
374 case Block_ClientArenaMallocd:
375 case Block_ClientArenaFree:
376 case Block_ValgrindArenaMallocd:
377 case Block_ValgrindArenaFree: return True;
379 default: vg_assert (0);
383 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
385 if (tinfo.tnr != 0)
386 return "#";
387 else
388 return "";
391 static UInt tnr_else_tid (ThreadInfo tinfo)
393 if (tinfo.tnr != 0)
394 return tinfo.tnr;
395 else
396 return tinfo.tid;
399 static const HChar* pp_SegKind ( SegKind sk )
401 switch (sk) {
402 case SkAnonC: return "anonymous";
403 case SkFileC: return "mapped file";
404 case SkShmC: return "shared memory";
405 default: vg_assert(0);
409 static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc,
410 Bool maybe_gcc )
412 const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
413 const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
415 vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
417 switch (ai->tag) {
418 case Addr_Undescribed:
419 VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed");
421 case Addr_Unknown:
422 if (maybe_gcc) {
423 VG_(emit)( "%sAddress 0x%llx is just below the stack ptr. "
424 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
425 xpre, (ULong)a, xpost );
426 } else {
427 VG_(emit)( "%sAddress 0x%llx "
428 "is not stack'd, malloc'd or %s%s\n",
429 xpre,
430 (ULong)a,
431 mc ? "(recently) free'd" : "on a free list",
432 xpost );
434 break;
436 case Addr_Stack:
437 VG_(emit)( "%sAddress 0x%llx is on thread %s%d's stack%s\n",
438 xpre, (ULong)a,
439 opt_tnr_prefix (ai->Addr.Stack.tinfo),
440 tnr_else_tid (ai->Addr.Stack.tinfo),
441 xpost );
442 if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) {
443 const HChar *fn;
444 Bool hasfn;
445 const HChar *file;
446 Bool hasfile;
447 UInt linenum;
448 Bool haslinenum;
449 PtrdiffT offset;
451 if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP,
452 &offset))
453 haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset,
454 &linenum);
455 else
456 haslinenum = False;
458 hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file);
460 HChar strlinenum[16] = ""; // large enough
461 if (hasfile && haslinenum)
462 VG_(sprintf)(strlinenum, "%d", linenum);
464 hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn);
466 if (hasfn || hasfile)
467 VG_(emit)( "%sin frame #%d, created by %s (%s:%s)%s\n",
468 xpre,
469 ai->Addr.Stack.frameNo,
470 hasfn ? fn : "???",
471 hasfile ? file : "???", strlinenum,
472 xpost );
474 switch (ai->Addr.Stack.stackPos) {
475 case StackPos_stacked: break; // nothing more to say
477 case StackPos_below_stack_ptr:
478 case StackPos_guard_page:
479 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
480 xpre,
481 ai->Addr.Stack.stackPos == StackPos_guard_page ?
482 "In stack guard protected page, " : "",
483 - ai->Addr.Stack.spoffset,
484 xpost);
485 // Note: we change the sign of spoffset as the message speaks
486 // about the nr of bytes below stack pointer.
487 break;
489 default: vg_assert(0);
491 break;
493 case Addr_Block: {
494 SizeT block_szB = ai->Addr.Block.block_szB;
495 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
496 SizeT delta;
497 const HChar* relative;
499 if (rwoffset < 0) {
500 delta = (SizeT)(-rwoffset);
501 relative = "before";
502 } else if (rwoffset >= block_szB) {
503 delta = rwoffset - block_szB;
504 relative = "after";
505 } else {
506 delta = rwoffset;
507 relative = "inside";
509 if (is_arena_BlockKind (ai->Addr.Block.block_kind))
510 VG_(emit)(
511 "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
512 " in arena \"%s\"%s\n",
513 xpre,
514 a, delta,
515 relative,
516 ai->Addr.Block.block_kind==Block_ClientArenaMallocd
517 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
518 ? "" : "n unallocated",
519 block_szB,
520 ai->Addr.Block.block_desc, // arena name
521 xpost
523 else
524 VG_(emit)(
525 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
526 xpre,
527 a, delta,
528 relative,
529 ai->Addr.Block.block_desc,
530 block_szB,
531 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
532 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
533 : "client-defined",
534 xpost
536 if (ai->Addr.Block.block_kind==Block_Mallocd) {
537 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
538 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
540 else if (ai->Addr.Block.block_kind==Block_Freed) {
541 VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
542 if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
543 VG_(emit)(
544 "%sBlock was alloc'd at%s\n",
545 xpre,
546 xpost
548 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
551 else if (ai->Addr.Block.block_kind==Block_MempoolChunk
552 || ai->Addr.Block.block_kind==Block_UserG) {
553 // client-defined
554 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
555 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
556 /* Nb: cannot have a freed_at, as a freed client-defined block
557 has a Block_Freed block_kind. */
558 } else {
559 // Client or Valgrind arena. At least currently, we never
560 // have stacktraces for these.
561 vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
562 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
564 if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
565 VG_(emit)(
566 "%sBlock was alloc'd by thread %s%d%s\n",
567 xpre,
568 opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
569 tnr_else_tid (ai->Addr.Block.alloc_tinfo),
570 xpost
572 break;
575 case Addr_DataSym:
576 VG_(emit)( "%sAddress 0x%llx is %llu bytes "
577 "inside data symbol \"%pS\"%s\n",
578 xpre,
579 (ULong)a,
580 (ULong)ai->Addr.DataSym.offset,
581 ai->Addr.DataSym.name,
582 xpost );
583 break;
585 case Addr_Variable:
586 /* Note, no need for XML tags here, because descr1/2 will
587 already have <auxwhat> or <xauxwhat>s on them, in XML
588 mode. */
589 if (ai->Addr.Variable.descr1)
590 VG_(emit)( "%s%s\n",
591 VG_(clo_xml) ? " " : " ",
592 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
593 if (ai->Addr.Variable.descr2)
594 VG_(emit)( "%s%s\n",
595 VG_(clo_xml) ? " " : " ",
596 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
597 break;
599 case Addr_SectKind:
600 VG_(emit)( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
601 xpre,
602 (ULong)a,
603 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
604 ai->Addr.SectKind.objname,
605 xpost );
606 if (ai->Addr.SectKind.kind == Vg_SectText) {
607 /* To better describe the address in a text segment,
608 pp a dummy stacktrace made of this single address. */
609 VG_(pp_StackTrace)( &a, 1 );
611 break;
613 case Addr_BrkSegment:
614 if (a < ai->Addr.BrkSegment.brk_limit)
615 VG_(emit)( "%sAddress 0x%llx is in the brk data segment"
616 " 0x%llx-0x%llx%s\n",
617 xpre,
618 (ULong)a,
619 (ULong)VG_(brk_base),
620 (ULong)ai->Addr.BrkSegment.brk_limit - 1,
621 xpost );
622 else
623 VG_(emit)( "%sAddress 0x%llx is %lu bytes after "
624 "the brk data segment limit"
625 " 0x%llx%s\n",
626 xpre,
627 (ULong)a,
628 a - ai->Addr.BrkSegment.brk_limit,
629 (ULong)ai->Addr.BrkSegment.brk_limit,
630 xpost );
631 break;
633 case Addr_SegmentKind:
634 VG_(emit)( "%sAddress 0x%llx is in "
635 "a %s%s%s %s%s%pS segment%s\n",
636 xpre,
637 (ULong)a,
638 ai->Addr.SegmentKind.hasR ? "r" : "-",
639 ai->Addr.SegmentKind.hasW ? "w" : "-",
640 ai->Addr.SegmentKind.hasX ? "x" : "-",
641 pp_SegKind(ai->Addr.SegmentKind.segkind),
642 ai->Addr.SegmentKind.filename ?
643 " " : "",
644 ai->Addr.SegmentKind.filename ?
645 ai->Addr.SegmentKind.filename : "",
646 xpost );
647 break;
649 default:
650 VG_(core_panic)("mc_pp_AddrInfo");
654 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
656 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
659 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
661 pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
665 /*--------------------------------------------------------------------*/
666 /*--- end m_addrinfo.c ---*/
667 /*--------------------------------------------------------------------*/