memcheck/tests/libstdc++.supp: rename suppression
[valgrind.git] / coregrind / m_addrinfo.c
blob1796eb8152e0e5f26fb9a30c06a992ebdc08a502
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, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics.h"
31 #include "pub_core_clientstate.h"
32 #include "pub_core_libcassert.h"
33 #include "pub_core_libcbase.h"
34 #include "pub_core_libcprint.h"
35 #include "pub_core_xarray.h"
36 #include "pub_core_debuginfo.h"
37 #include "pub_core_execontext.h"
38 #include "pub_core_addrinfo.h"
39 #include "pub_core_mallocfree.h"
40 #include "pub_core_machine.h"
41 #include "pub_core_options.h"
42 #include "pub_core_threadstate.h"
43 #include "pub_core_stacktrace.h"
44 #include "pub_core_stacks.h"
45 #include "pub_core_aspacemgr.h"
47 /* Returns the tid whose stack includes the address a.
48 If not found, returns VG_INVALID_THREADID. */
49 static ThreadId find_tid_with_stack_containing (Addr a)
51 ThreadId tid;
52 Addr start, end;
54 start = 0;
55 end = 0;
56 VG_(stack_limits)(a, &start, &end);
57 if (start == end) {
58 // No stack found
59 vg_assert (start == 0 && end == 0);
60 return VG_INVALID_THREADID;
63 /* Stack limits found. Search the tid to which this stack belongs. */
64 vg_assert (start <= a);
65 vg_assert (a <= end);
67 /* The stack end (highest accessible byte) is for sure inside the 'active'
68 part of the stack of the searched tid.
69 So, scan all 'active' stacks with VG_(thread_stack_reset_iter) ... */
71 Addr stack_min, stack_max;
73 VG_(thread_stack_reset_iter)(&tid);
74 while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
75 if (stack_min <= end && end <= stack_max)
76 return tid;
80 /* We can arrive here if a stack was registered with wrong bounds
81 (e.g. end above the highest addressable byte)
82 and/or if the thread for the registered stack is dead, but
83 the stack was not unregistered. */
84 return VG_INVALID_THREADID;
87 void VG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai )
89 VgSectKind sect;
91 /* -- Perhaps the variable type/location data describes it? -- */
92 ai->Addr.Variable.descr1
93 = VG_(newXA)( VG_(malloc), "mc.da.descr1",
94 VG_(free), sizeof(HChar) );
95 ai->Addr.Variable.descr2
96 = VG_(newXA)( VG_(malloc), "mc.da.descr2",
97 VG_(free), sizeof(HChar) );
99 (void) VG_(get_data_description)( ai->Addr.Variable.descr1,
100 ai->Addr.Variable.descr2, ep, a );
101 /* If there's nothing in descr1/2, free them. Why is it safe to
102 VG_(indexXA) at zero here? Because VG_(get_data_description)
103 guarantees to zero terminate descr1/2 regardless of the outcome
104 of the call. So there's always at least one element in each XA
105 after the call.
107 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr1, 0 ))) {
108 VG_(deleteXA)( ai->Addr.Variable.descr1 );
109 ai->Addr.Variable.descr1 = NULL;
111 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
112 VG_(deleteXA)( ai->Addr.Variable.descr2 );
113 ai->Addr.Variable.descr2 = NULL;
115 /* Assume (assert) that VG_(get_data_description) fills in descr1
116 before it fills in descr2 */
117 if (ai->Addr.Variable.descr1 == NULL)
118 vg_assert(ai->Addr.Variable.descr2 == NULL);
119 /* So did we get lucky? */
120 if (ai->Addr.Variable.descr1 != NULL) {
121 ai->tag = Addr_Variable;
122 return;
124 /* -- Have a look at the low level data symbols - perhaps it's in
125 there. -- */
126 const HChar *name;
127 if (VG_(get_datasym_and_offset)(
128 ep, a, &name,
129 &ai->Addr.DataSym.offset )) {
130 ai->Addr.DataSym.name = VG_(strdup)("mc.da.dsname", name);
131 ai->tag = Addr_DataSym;
132 return;
134 /* -- Perhaps it's on a thread's stack? -- */
136 ThreadId tid;
137 Addr stack_min, stack_max;
138 VG_(thread_stack_reset_iter)(&tid);
139 while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
140 if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
141 Addr ips[VG_(clo_backtrace_size)],
142 sps[VG_(clo_backtrace_size)];
143 UInt n_frames;
144 UInt f;
146 ai->tag = Addr_Stack;
147 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
148 ai->Addr.Stack.tinfo.tid = tid;
149 ai->Addr.Stack.epoch = ep;
150 ai->Addr.Stack.IP = 0;
151 ai->Addr.Stack.frameNo = -1;
152 ai->Addr.Stack.stackPos = StackPos_stacked;
153 ai->Addr.Stack.spoffset = 0; // Unused.
154 /* It is on thread tid stack. Build a stacktrace, and
155 find the frame sp[f] .. sp[f+1] where the address is.
156 Store the found frameNo and the corresponding IP in
157 the description.
158 When description is printed, IP will be translated to
159 the function name containing IP.
160 Before accepting to describe addr with sp[f] .. sp[f+1],
161 we verify the sp looks sane: reasonably sized frame,
162 inside the stack.
163 We could check the ABI required alignment for sp (what is it?)
164 is respected, except for the innermost stack pointer ? */
165 n_frames = VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size),
166 sps, NULL, 0/*first_ip_delta*/ );
167 for (f = 0; f < n_frames-1; f++) {
168 if (sps[f] <= a && a < sps[f+1]
169 && sps[f+1] - sps[f] <= 0x4000000 // 64 MB, arbitrary
170 && sps[f+1] <= stack_max
171 && sps[f] >= stack_min - VG_STACK_REDZONE_SZB) {
172 ai->Addr.Stack.frameNo = f;
173 ai->Addr.Stack.IP = ips[f];
174 break;
177 return;
182 /* -- Maybe it is in one of the m_mallocfree.c arenas. -- */
184 AddrArenaInfo aai;
185 VG_(describe_arena_addr) ( a, &aai );
186 if (aai.name != NULL) {
187 ai->tag = Addr_Block;
188 if (aai.aid == VG_AR_CLIENT)
189 ai->Addr.Block.block_kind
190 = aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd;
191 else
192 ai->Addr.Block.block_kind
193 = aai.free
194 ? Block_ValgrindArenaFree : Block_ValgrindArenaMallocd;
195 ai->Addr.Block.block_desc = aai.name;
196 ai->Addr.Block.block_szB = aai.block_szB;
197 ai->Addr.Block.rwoffset = aai.rwoffset;
198 ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
199 VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
200 ai->Addr.Block.freed_at = VG_(null_ExeContext)();
201 return;
205 /* -- last ditch attempt at classification -- */
206 sect = VG_(DebugInfo_sect_kind)( &name, a);
207 if (sect != Vg_SectUnknown) {
208 ai->tag = Addr_SectKind;
209 ai->Addr.SectKind.objname = VG_(strdup)("mc.da.dsname", name);
210 ai->Addr.SectKind.kind = sect;
211 return;
214 /* -- and yet another last ditch attempt at classification -- */
215 /* If the address is in a stack between the stack bottom (highest byte)
216 and the current stack ptr, it will have been already described above.
217 But maybe it is in a stack, but below the stack ptr (typical
218 for a 'use after return' or in the stack guard page (thread stack
219 too small). */
221 ThreadId tid;
222 StackPos stackPos = StackPos_stacked;
223 // Default init to StackPos_stacked, to silence gcc warning.
224 // We assert this value is overridden if a stack descr is produced.
226 // First try to find a tid with stack containing a
227 tid = find_tid_with_stack_containing (a);
228 if (tid != VG_INVALID_THREADID) {
229 /* Should be below stack pointer, as if it is >= SP, it
230 will have been described as StackPos_stacked above. */
231 stackPos = StackPos_below_stack_ptr;
232 } else {
233 /* Try to find a stack with guard page containing a.
234 For this, check if a is in a page mapped without r, w and x. */
235 const NSegment *seg = VG_(am_find_nsegment) (a);
236 if (seg != NULL && seg->kind == SkAnonC
237 && !seg->hasR && !seg->hasW && !seg->hasX) {
238 /* This looks a plausible guard page. Check if a is close to
239 the start of stack (lowest byte). */
240 tid = find_tid_with_stack_containing (VG_PGROUNDUP(a+1));
241 if (tid != VG_INVALID_THREADID)
242 stackPos = StackPos_guard_page;
246 if (tid != VG_INVALID_THREADID) {
247 ai->tag = Addr_Stack;
248 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
249 ai->Addr.Stack.tinfo.tid = tid;
250 ai->Addr.Stack.epoch = ep;
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%lx is just below the stack ptr. "
424 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
425 xpre, a, xpost );
426 } else {
427 VG_(emit)( "%sAddress 0x%lx "
428 "is not stack'd, malloc'd or %s%s\n",
429 xpre, a,
430 mc ? "(recently) free'd" : "on a free list",
431 xpost );
433 break;
435 case Addr_Stack:
436 VG_(emit)( "%sAddress 0x%lx is on thread %s%u's stack%s\n",
437 xpre, a,
438 opt_tnr_prefix (ai->Addr.Stack.tinfo),
439 tnr_else_tid (ai->Addr.Stack.tinfo),
440 xpost );
441 if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) {
442 const HChar *fn;
443 Bool hasfn;
444 const HChar *file;
445 Bool hasfile;
446 UInt linenum;
447 Bool haslinenum;
448 PtrdiffT offset;
450 if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.epoch,
451 ai->Addr.Stack.IP,
452 &offset))
453 haslinenum = VG_(get_linenum) (ai->Addr.Stack.epoch,
454 ai->Addr.Stack.IP - offset,
455 &linenum);
456 else
457 haslinenum = False;
459 hasfile = VG_(get_filename)(ai->Addr.Stack.epoch,
460 ai->Addr.Stack.IP, &file);
462 HChar strlinenum[16] = ""; // large enough
463 if (hasfile && haslinenum)
464 VG_(sprintf)(strlinenum, "%u", linenum);
466 hasfn = VG_(get_fnname)(ai->Addr.Stack.epoch,
467 ai->Addr.Stack.IP, &fn);
469 if (hasfn || hasfile)
470 VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n",
471 xpre,
472 ai->Addr.Stack.frameNo,
473 hasfn ? fn : "???",
474 hasfile ? file : "???", strlinenum,
475 xpost );
477 switch (ai->Addr.Stack.stackPos) {
478 case StackPos_stacked: break; // nothing more to say
480 case StackPos_below_stack_ptr:
481 case StackPos_guard_page:
482 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
483 xpre,
484 ai->Addr.Stack.stackPos == StackPos_guard_page ?
485 "In stack guard protected page, " : "",
486 - ai->Addr.Stack.spoffset,
487 xpost);
488 // Note: we change the sign of spoffset as the message speaks
489 // about the nr of bytes below stack pointer.
490 break;
492 default: vg_assert(0);
494 break;
496 case Addr_Block: {
497 SizeT block_szB = ai->Addr.Block.block_szB;
498 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
499 SizeT delta;
500 const HChar* relative;
502 if (rwoffset < 0) {
503 delta = (SizeT)(-rwoffset);
504 relative = "before";
505 } else if (rwoffset >= block_szB) {
506 delta = rwoffset - block_szB;
507 relative = "after";
508 } else {
509 delta = rwoffset;
510 relative = "inside";
512 if (is_arena_BlockKind (ai->Addr.Block.block_kind))
513 VG_(emit)(
514 "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
515 " in arena \"%s\"%s\n",
516 xpre,
517 a, delta,
518 relative,
519 ai->Addr.Block.block_kind==Block_ClientArenaMallocd
520 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
521 ? "" : "n unallocated",
522 block_szB,
523 ai->Addr.Block.block_desc, // arena name
524 xpost
526 else
527 VG_(emit)(
528 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
529 xpre,
530 a, delta,
531 relative,
532 ai->Addr.Block.block_desc,
533 block_szB,
534 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
535 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
536 : "client-defined",
537 xpost
539 if (ai->Addr.Block.block_kind==Block_Mallocd) {
540 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
541 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
543 else if (ai->Addr.Block.block_kind==Block_Freed) {
544 VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
545 if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
546 VG_(emit)(
547 "%sBlock was alloc'd at%s\n",
548 xpre,
549 xpost
551 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
554 else if (ai->Addr.Block.block_kind==Block_MempoolChunk
555 || ai->Addr.Block.block_kind==Block_UserG) {
556 // client-defined
557 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
558 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
559 /* Nb: cannot have a freed_at, as a freed client-defined block
560 has a Block_Freed block_kind. */
561 } else {
562 // Client or Valgrind arena. At least currently, we never
563 // have stacktraces for these.
564 vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
565 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
567 if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
568 VG_(emit)(
569 "%sBlock was alloc'd by thread %s%u%s\n",
570 xpre,
571 opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
572 tnr_else_tid (ai->Addr.Block.alloc_tinfo),
573 xpost
575 break;
578 case Addr_DataSym:
579 VG_(emit)( "%sAddress 0x%lx is %llu bytes "
580 "inside data symbol \"%ps\"%s\n",
581 xpre, a,
582 (ULong)ai->Addr.DataSym.offset,
583 ai->Addr.DataSym.name,
584 xpost );
585 break;
587 case Addr_Variable:
588 /* Note, no need for XML tags here, because descr1/2 will
589 already have <auxwhat> or <xauxwhat>s on them, in XML
590 mode. */
591 if (ai->Addr.Variable.descr1)
592 VG_(emit)( "%s%s\n",
593 VG_(clo_xml) ? " " : " ",
594 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
595 if (ai->Addr.Variable.descr2)
596 VG_(emit)( "%s%s\n",
597 VG_(clo_xml) ? " " : " ",
598 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
599 break;
601 case Addr_SectKind:
602 VG_(emit)( "%sAddress 0x%lx is in the %ps segment of %ps%s\n",
603 xpre, a,
604 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
605 ai->Addr.SectKind.objname,
606 xpost );
607 if (ai->Addr.SectKind.kind == Vg_SectText) {
608 /* To better describe the address in a text segment,
609 pp a dummy stacktrace made of this single address. */
610 VG_(pp_StackTrace)( VG_(current_DiEpoch)(), &a, 1 );
612 break;
614 case Addr_BrkSegment:
615 if (a < ai->Addr.BrkSegment.brk_limit)
616 VG_(emit)( "%sAddress 0x%lx is in the brk data segment"
617 " 0x%lx-0x%lx%s\n",
618 xpre, a,
619 VG_(brk_base),
620 ai->Addr.BrkSegment.brk_limit - 1,
621 xpost );
622 else
623 VG_(emit)( "%sAddress 0x%lx is %lu bytes after "
624 "the brk data segment limit"
625 " 0x%lx%s\n",
626 xpre, a,
627 a - ai->Addr.BrkSegment.brk_limit,
628 ai->Addr.BrkSegment.brk_limit,
629 xpost );
630 break;
632 case Addr_SegmentKind:
633 VG_(emit)( "%sAddress 0x%lx is in "
634 "a %s%s%s %s%s%ps segment%s\n",
635 xpre,
637 ai->Addr.SegmentKind.hasR ? "r" : "-",
638 ai->Addr.SegmentKind.hasW ? "w" : "-",
639 ai->Addr.SegmentKind.hasX ? "x" : "-",
640 pp_SegKind(ai->Addr.SegmentKind.segkind),
641 ai->Addr.SegmentKind.filename ?
642 " " : "",
643 ai->Addr.SegmentKind.filename ?
644 ai->Addr.SegmentKind.filename : "",
645 xpost );
646 break;
648 default:
649 VG_(core_panic)("mc_pp_AddrInfo");
653 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
655 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
658 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
660 pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
664 /*--------------------------------------------------------------------*/
665 /*--- end m_addrinfo.c ---*/
666 /*--------------------------------------------------------------------*/