Add DRD suppression patterns for races triggered by std::ostream
[valgrind.git] / coregrind / m_addrinfo.c
blobd22a99e58d993414b61397d61b8a440acf767ab2
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-2017 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) ( DiEpoch ep, 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, ep, 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 ep, 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.epoch = ep;
152 ai->Addr.Stack.IP = 0;
153 ai->Addr.Stack.frameNo = -1;
154 ai->Addr.Stack.stackPos = StackPos_stacked;
155 ai->Addr.Stack.spoffset = 0; // Unused.
156 /* It is on thread tid stack. Build a stacktrace, and
157 find the frame sp[f] .. sp[f+1] where the address is.
158 Store the found frameNo and the corresponding IP in
159 the description.
160 When description is printed, IP will be translated to
161 the function name containing IP.
162 Before accepting to describe addr with sp[f] .. sp[f+1],
163 we verify the sp looks sane: reasonably sized frame,
164 inside the stack.
165 We could check the ABI required alignment for sp (what is it?)
166 is respected, except for the innermost stack pointer ? */
167 n_frames = VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size),
168 sps, NULL, 0/*first_ip_delta*/ );
169 for (f = 0; f < n_frames-1; f++) {
170 if (sps[f] <= a && a < sps[f+1]
171 && sps[f+1] - sps[f] <= 0x4000000 // 64 MB, arbitrary
172 && sps[f+1] <= stack_max
173 && sps[f] >= stack_min - VG_STACK_REDZONE_SZB) {
174 ai->Addr.Stack.frameNo = f;
175 ai->Addr.Stack.IP = ips[f];
176 break;
179 return;
184 /* -- Maybe it is in one of the m_mallocfree.c arenas. -- */
186 AddrArenaInfo aai;
187 VG_(describe_arena_addr) ( a, &aai );
188 if (aai.name != NULL) {
189 ai->tag = Addr_Block;
190 if (aai.aid == VG_AR_CLIENT)
191 ai->Addr.Block.block_kind
192 = aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd;
193 else
194 ai->Addr.Block.block_kind
195 = aai.free
196 ? Block_ValgrindArenaFree : Block_ValgrindArenaMallocd;
197 ai->Addr.Block.block_desc = aai.name;
198 ai->Addr.Block.block_szB = aai.block_szB;
199 ai->Addr.Block.rwoffset = aai.rwoffset;
200 ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
201 VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
202 ai->Addr.Block.freed_at = VG_(null_ExeContext)();
203 return;
207 /* -- last ditch attempt at classification -- */
208 sect = VG_(DebugInfo_sect_kind)( &name, a);
209 if (sect != Vg_SectUnknown) {
210 ai->tag = Addr_SectKind;
211 ai->Addr.SectKind.objname = VG_(strdup)("mc.da.dsname", name);
212 ai->Addr.SectKind.kind = sect;
213 return;
216 /* -- and yet another last ditch attempt at classification -- */
217 /* If the address is in a stack between the stack bottom (highest byte)
218 and the current stack ptr, it will have been already described above.
219 But maybe it is in a stack, but below the stack ptr (typical
220 for a 'use after return' or in the stack guard page (thread stack
221 too small). */
223 ThreadId tid;
224 StackPos stackPos = StackPos_stacked;
225 // Default init to StackPos_stacked, to silence gcc warning.
226 // We assert this value is overridden if a stack descr is produced.
228 // First try to find a tid with stack containing a
229 tid = find_tid_with_stack_containing (a);
230 if (tid != VG_INVALID_THREADID) {
231 /* Should be below stack pointer, as if it is >= SP, it
232 will have been described as StackPos_stacked above. */
233 stackPos = StackPos_below_stack_ptr;
234 } else {
235 /* Try to find a stack with guard page containing a.
236 For this, check if a is in a page mapped without r, w and x. */
237 const NSegment *seg = VG_(am_find_nsegment) (a);
238 if (seg != NULL && seg->kind == SkAnonC
239 && !seg->hasR && !seg->hasW && !seg->hasX) {
240 /* This looks a plausible guard page. Check if a is close to
241 the start of stack (lowest byte). */
242 tid = find_tid_with_stack_containing (VG_PGROUNDUP(a+1));
243 if (tid != VG_INVALID_THREADID)
244 stackPos = StackPos_guard_page;
248 if (tid != VG_INVALID_THREADID) {
249 ai->tag = Addr_Stack;
250 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
251 ai->Addr.Stack.tinfo.tid = tid;
252 ai->Addr.Stack.epoch = ep;
253 ai->Addr.Stack.IP = 0;
254 ai->Addr.Stack.frameNo = -1;
255 vg_assert (stackPos != StackPos_stacked);
256 ai->Addr.Stack.stackPos = stackPos;
257 vg_assert (a < VG_(get_SP)(tid));
258 ai->Addr.Stack.spoffset = a - VG_(get_SP)(tid);
259 return;
263 /* -- and yet another last ditch attempt at classification -- */
264 /* Try to find a segment belonging to the client. */
266 const NSegment *seg = VG_(am_find_nsegment) (a);
268 /* Special case to detect the brk data segment. */
269 if (seg != NULL
270 #if defined(VGO_solaris)
271 && (seg->kind == SkAnonC || seg->kind == SkFileC)
272 #else
273 && seg->kind == SkAnonC
274 #endif /* VGO_solaris */
275 && VG_(brk_limit) >= seg->start
276 && VG_(brk_limit) <= seg->end+1) {
277 /* Address a is in a Anon Client segment which contains
278 VG_(brk_limit). So, this segment is the brk data segment
279 as initimg-linux.c:setup_client_dataseg maps an anonymous
280 segment followed by a reservation, with one reservation
281 page that will never be used by syswrap-generic.c:do_brk,
282 when increasing VG_(brk_limit).
283 So, the brk data segment will never be merged with the
284 next segment, and so an address in that area will
285 either be in the brk data segment, or in the unmapped
286 part of the brk data segment reservation. */
287 ai->tag = Addr_BrkSegment;
288 ai->Addr.BrkSegment.brk_limit = VG_(brk_limit);
289 return;
292 if (seg != NULL
293 && (seg->kind == SkAnonC
294 || seg->kind == SkFileC
295 || seg->kind == SkShmC)) {
296 ai->tag = Addr_SegmentKind;
297 ai->Addr.SegmentKind.segkind = seg->kind;
298 ai->Addr.SegmentKind.filename = NULL;
299 if (seg->kind == SkFileC)
300 ai->Addr.SegmentKind.filename
301 = VG_(strdup)("mc.da.skfname", VG_(am_get_filename)(seg));
302 ai->Addr.SegmentKind.hasR = seg->hasR;
303 ai->Addr.SegmentKind.hasW = seg->hasW;
304 ai->Addr.SegmentKind.hasX = seg->hasX;
305 return;
309 /* -- Clueless ... -- */
310 ai->tag = Addr_Unknown;
311 return;
314 void VG_(initThreadInfo) (ThreadInfo *tinfo)
316 tinfo->tid = 0;
317 tinfo->tnr = 0;
320 void VG_(clear_addrinfo) ( AddrInfo* ai)
322 switch (ai->tag) {
323 case Addr_Undescribed:
324 break;
326 case Addr_Unknown:
327 break;
329 case Addr_Stack:
330 break;
332 case Addr_Block:
333 break;
335 case Addr_DataSym:
336 VG_(free)(ai->Addr.DataSym.name);
337 break;
339 case Addr_Variable:
340 if (ai->Addr.Variable.descr1 != NULL) {
341 VG_(deleteXA)( ai->Addr.Variable.descr1 );
342 ai->Addr.Variable.descr1 = NULL;
344 if (ai->Addr.Variable.descr2 != NULL) {
345 VG_(deleteXA)( ai->Addr.Variable.descr2 );
346 ai->Addr.Variable.descr2 = NULL;
348 break;
350 case Addr_SectKind:
351 VG_(free)(ai->Addr.SectKind.objname);
352 break;
354 case Addr_BrkSegment:
355 break;
357 case Addr_SegmentKind:
358 VG_(free)(ai->Addr.SegmentKind.filename);
359 break;
361 default:
362 VG_(core_panic)("VG_(clear_addrinfo)");
365 ai->tag = Addr_Undescribed;
368 static Bool is_arena_BlockKind(BlockKind bk)
370 switch (bk) {
371 case Block_Mallocd:
372 case Block_Freed:
373 case Block_MempoolChunk:
374 case Block_UserG: return False;
376 case Block_ClientArenaMallocd:
377 case Block_ClientArenaFree:
378 case Block_ValgrindArenaMallocd:
379 case Block_ValgrindArenaFree: return True;
381 default: vg_assert (0);
385 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
387 if (tinfo.tnr != 0)
388 return "#";
389 else
390 return "";
393 static UInt tnr_else_tid (ThreadInfo tinfo)
395 if (tinfo.tnr != 0)
396 return tinfo.tnr;
397 else
398 return tinfo.tid;
401 static const HChar* pp_SegKind ( SegKind sk )
403 switch (sk) {
404 case SkAnonC: return "anonymous";
405 case SkFileC: return "mapped file";
406 case SkShmC: return "shared memory";
407 default: vg_assert(0);
411 static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc,
412 Bool maybe_gcc )
414 const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
415 const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
417 vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
419 switch (ai->tag) {
420 case Addr_Undescribed:
421 VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed");
423 case Addr_Unknown:
424 if (maybe_gcc) {
425 VG_(emit)( "%sAddress 0x%lx is just below the stack ptr. "
426 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
427 xpre, a, xpost );
428 } else {
429 VG_(emit)( "%sAddress 0x%lx "
430 "is not stack'd, malloc'd or %s%s\n",
431 xpre, a,
432 mc ? "(recently) free'd" : "on a free list",
433 xpost );
435 break;
437 case Addr_Stack:
438 VG_(emit)( "%sAddress 0x%lx is on thread %s%u's stack%s\n",
439 xpre, a,
440 opt_tnr_prefix (ai->Addr.Stack.tinfo),
441 tnr_else_tid (ai->Addr.Stack.tinfo),
442 xpost );
443 if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) {
444 const HChar *fn;
445 Bool hasfn;
446 const HChar *file;
447 Bool hasfile;
448 UInt linenum;
449 Bool haslinenum;
450 PtrdiffT offset;
452 if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.epoch,
453 ai->Addr.Stack.IP,
454 &offset))
455 haslinenum = VG_(get_linenum) (ai->Addr.Stack.epoch,
456 ai->Addr.Stack.IP - offset,
457 &linenum);
458 else
459 haslinenum = False;
461 hasfile = VG_(get_filename)(ai->Addr.Stack.epoch,
462 ai->Addr.Stack.IP, &file);
464 HChar strlinenum[16] = ""; // large enough
465 if (hasfile && haslinenum)
466 VG_(sprintf)(strlinenum, "%u", linenum);
468 hasfn = VG_(get_fnname)(ai->Addr.Stack.epoch,
469 ai->Addr.Stack.IP, &fn);
471 if (hasfn || hasfile)
472 VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n",
473 xpre,
474 ai->Addr.Stack.frameNo,
475 hasfn ? fn : "???",
476 hasfile ? file : "???", strlinenum,
477 xpost );
479 switch (ai->Addr.Stack.stackPos) {
480 case StackPos_stacked: break; // nothing more to say
482 case StackPos_below_stack_ptr:
483 case StackPos_guard_page:
484 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
485 xpre,
486 ai->Addr.Stack.stackPos == StackPos_guard_page ?
487 "In stack guard protected page, " : "",
488 - ai->Addr.Stack.spoffset,
489 xpost);
490 // Note: we change the sign of spoffset as the message speaks
491 // about the nr of bytes below stack pointer.
492 break;
494 default: vg_assert(0);
496 break;
498 case Addr_Block: {
499 SizeT block_szB = ai->Addr.Block.block_szB;
500 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
501 SizeT delta;
502 const HChar* relative;
504 if (rwoffset < 0) {
505 delta = (SizeT)(-rwoffset);
506 relative = "before";
507 } else if (rwoffset >= block_szB) {
508 delta = rwoffset - block_szB;
509 relative = "after";
510 } else {
511 delta = rwoffset;
512 relative = "inside";
514 if (is_arena_BlockKind (ai->Addr.Block.block_kind))
515 VG_(emit)(
516 "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
517 " in arena \"%s\"%s\n",
518 xpre,
519 a, delta,
520 relative,
521 ai->Addr.Block.block_kind==Block_ClientArenaMallocd
522 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
523 ? "" : "n unallocated",
524 block_szB,
525 ai->Addr.Block.block_desc, // arena name
526 xpost
528 else
529 VG_(emit)(
530 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
531 xpre,
532 a, delta,
533 relative,
534 ai->Addr.Block.block_desc,
535 block_szB,
536 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
537 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
538 : "client-defined",
539 xpost
541 if (ai->Addr.Block.block_kind==Block_Mallocd) {
542 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
543 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
545 else if (ai->Addr.Block.block_kind==Block_Freed) {
546 VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
547 if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
548 VG_(emit)(
549 "%sBlock was alloc'd at%s\n",
550 xpre,
551 xpost
553 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
556 else if (ai->Addr.Block.block_kind==Block_MempoolChunk
557 || ai->Addr.Block.block_kind==Block_UserG) {
558 // client-defined
559 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
560 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
561 /* Nb: cannot have a freed_at, as a freed client-defined block
562 has a Block_Freed block_kind. */
563 } else {
564 // Client or Valgrind arena. At least currently, we never
565 // have stacktraces for these.
566 vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
567 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
569 if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
570 VG_(emit)(
571 "%sBlock was alloc'd by thread %s%u%s\n",
572 xpre,
573 opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
574 tnr_else_tid (ai->Addr.Block.alloc_tinfo),
575 xpost
577 break;
580 case Addr_DataSym:
581 VG_(emit)( "%sAddress 0x%lx is %llu bytes "
582 "inside data symbol \"%ps\"%s\n",
583 xpre, a,
584 (ULong)ai->Addr.DataSym.offset,
585 ai->Addr.DataSym.name,
586 xpost );
587 break;
589 case Addr_Variable:
590 /* Note, no need for XML tags here, because descr1/2 will
591 already have <auxwhat> or <xauxwhat>s on them, in XML
592 mode. */
593 if (ai->Addr.Variable.descr1)
594 VG_(emit)( "%s%s\n",
595 VG_(clo_xml) ? " " : " ",
596 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
597 if (ai->Addr.Variable.descr2)
598 VG_(emit)( "%s%s\n",
599 VG_(clo_xml) ? " " : " ",
600 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
601 break;
603 case Addr_SectKind:
604 VG_(emit)( "%sAddress 0x%lx is in the %ps segment of %ps%s\n",
605 xpre, a,
606 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
607 ai->Addr.SectKind.objname,
608 xpost );
609 if (ai->Addr.SectKind.kind == Vg_SectText) {
610 /* To better describe the address in a text segment,
611 pp a dummy stacktrace made of this single address. */
612 VG_(pp_StackTrace)( VG_(current_DiEpoch)(), &a, 1 );
614 break;
616 case Addr_BrkSegment:
617 if (a < ai->Addr.BrkSegment.brk_limit)
618 VG_(emit)( "%sAddress 0x%lx is in the brk data segment"
619 " 0x%lx-0x%lx%s\n",
620 xpre, a,
621 VG_(brk_base),
622 ai->Addr.BrkSegment.brk_limit - 1,
623 xpost );
624 else
625 VG_(emit)( "%sAddress 0x%lx is %lu bytes after "
626 "the brk data segment limit"
627 " 0x%lx%s\n",
628 xpre, a,
629 a - ai->Addr.BrkSegment.brk_limit,
630 ai->Addr.BrkSegment.brk_limit,
631 xpost );
632 break;
634 case Addr_SegmentKind:
635 VG_(emit)( "%sAddress 0x%lx is in "
636 "a %s%s%s %s%s%ps segment%s\n",
637 xpre,
639 ai->Addr.SegmentKind.hasR ? "r" : "-",
640 ai->Addr.SegmentKind.hasW ? "w" : "-",
641 ai->Addr.SegmentKind.hasX ? "x" : "-",
642 pp_SegKind(ai->Addr.SegmentKind.segkind),
643 ai->Addr.SegmentKind.filename ?
644 " " : "",
645 ai->Addr.SegmentKind.filename ?
646 ai->Addr.SegmentKind.filename : "",
647 xpost );
648 break;
650 default:
651 VG_(core_panic)("mc_pp_AddrInfo");
655 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
657 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
660 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
662 pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
666 /*--------------------------------------------------------------------*/
667 /*--- end m_addrinfo.c ---*/
668 /*--------------------------------------------------------------------*/