FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_addrinfo.c
blob0d4624dbbcc927a03e17ed25b2fd0e8c51d3f52b
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;
245 * On FreeBSD the above heuristic fails since version 14.0
247 * I think that is because of a bug or at least a misfeature
248 * in the way that the kernel grows mmap'd MAP_STACK memory
249 * See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=277382
251 * I could add a lot of ugliness like
252 * "if the address is RW and sysctl security.bsd.stack_guard_page
253 * times the page size is PROT_NONE then it's a wonky guard page"
255 * Naaah.
259 if (tid != VG_INVALID_THREADID) {
260 ai->tag = Addr_Stack;
261 VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
262 ai->Addr.Stack.tinfo.tid = tid;
263 ai->Addr.Stack.epoch = ep;
264 ai->Addr.Stack.IP = 0;
265 ai->Addr.Stack.frameNo = -1;
266 vg_assert (stackPos != StackPos_stacked);
267 ai->Addr.Stack.stackPos = stackPos;
268 vg_assert (a < VG_(get_SP)(tid));
269 ai->Addr.Stack.spoffset = a - VG_(get_SP)(tid);
270 return;
274 /* -- and yet another last ditch attempt at classification -- */
275 /* Try to find a segment belonging to the client. */
277 const NSegment *seg = VG_(am_find_nsegment) (a);
279 /* Special case to detect the brk data segment. */
280 if (seg != NULL
281 #if defined(VGO_solaris)
282 && (seg->kind == SkAnonC || seg->kind == SkFileC)
283 #else
284 && seg->kind == SkAnonC
285 #endif /* VGO_solaris */
286 && VG_(brk_limit) >= seg->start
287 && VG_(brk_limit) <= seg->end+1) {
288 /* Address a is in a Anon Client segment which contains
289 VG_(brk_limit). So, this segment is the brk data segment
290 as initimg-linux.c:setup_client_dataseg maps an anonymous
291 segment followed by a reservation, with one reservation
292 page that will never be used by syswrap-generic.c:do_brk,
293 when increasing VG_(brk_limit).
294 So, the brk data segment will never be merged with the
295 next segment, and so an address in that area will
296 either be in the brk data segment, or in the unmapped
297 part of the brk data segment reservation. */
298 ai->tag = Addr_BrkSegment;
299 ai->Addr.BrkSegment.brk_limit = VG_(brk_limit);
300 return;
303 if (seg != NULL
304 && (seg->kind == SkAnonC
305 || seg->kind == SkFileC
306 || seg->kind == SkShmC)) {
307 ai->tag = Addr_SegmentKind;
308 ai->Addr.SegmentKind.segkind = seg->kind;
309 ai->Addr.SegmentKind.filename = NULL;
310 if (seg->kind == SkFileC)
311 ai->Addr.SegmentKind.filename
312 = VG_(strdup)("mc.da.skfname", VG_(am_get_filename)(seg));
313 ai->Addr.SegmentKind.hasR = seg->hasR;
314 ai->Addr.SegmentKind.hasW = seg->hasW;
315 ai->Addr.SegmentKind.hasX = seg->hasX;
316 return;
320 /* -- Clueless ... -- */
321 ai->tag = Addr_Unknown;
322 return;
325 void VG_(initThreadInfo) (ThreadInfo *tinfo)
327 tinfo->tid = 0;
328 tinfo->tnr = 0;
331 void VG_(clear_addrinfo) ( AddrInfo* ai)
333 switch (ai->tag) {
334 case Addr_Undescribed:
335 break;
337 case Addr_Unknown:
338 break;
340 case Addr_Stack:
341 break;
343 case Addr_Block:
344 break;
346 case Addr_DataSym:
347 VG_(free)(ai->Addr.DataSym.name);
348 break;
350 case Addr_Variable:
351 if (ai->Addr.Variable.descr1 != NULL) {
352 VG_(deleteXA)( ai->Addr.Variable.descr1 );
353 ai->Addr.Variable.descr1 = NULL;
355 if (ai->Addr.Variable.descr2 != NULL) {
356 VG_(deleteXA)( ai->Addr.Variable.descr2 );
357 ai->Addr.Variable.descr2 = NULL;
359 break;
361 case Addr_SectKind:
362 VG_(free)(ai->Addr.SectKind.objname);
363 break;
365 case Addr_BrkSegment:
366 break;
368 case Addr_SegmentKind:
369 VG_(free)(ai->Addr.SegmentKind.filename);
370 break;
372 default:
373 VG_(core_panic)("VG_(clear_addrinfo)");
376 ai->tag = Addr_Undescribed;
379 static Bool is_arena_BlockKind(BlockKind bk)
381 switch (bk) {
382 case Block_Mallocd:
383 case Block_Freed:
384 case Block_MempoolChunk:
385 case Block_UserG: return False;
387 case Block_ClientArenaMallocd:
388 case Block_ClientArenaFree:
389 case Block_ValgrindArenaMallocd:
390 case Block_ValgrindArenaFree: return True;
392 default: vg_assert (0);
396 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
398 if (tinfo.tnr != 0)
399 return "#";
400 else
401 return "";
404 static UInt tnr_else_tid (ThreadInfo tinfo)
406 if (tinfo.tnr != 0)
407 return tinfo.tnr;
408 else
409 return tinfo.tid;
412 static const HChar* pp_SegKind ( SegKind sk )
414 switch (sk) {
415 case SkAnonC: return "anonymous";
416 case SkFileC: return "mapped file";
417 case SkShmC: return "shared memory";
418 default: vg_assert(0);
422 static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc,
423 Bool maybe_gcc )
425 const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
426 const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
428 vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
430 switch (ai->tag) {
431 case Addr_Undescribed:
432 VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed");
434 case Addr_Unknown:
435 if (maybe_gcc) {
436 VG_(emit)( "%sAddress 0x%lx is just below the stack ptr. "
437 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
438 xpre, a, xpost );
439 } else {
440 VG_(emit)( "%sAddress 0x%lx "
441 "is not stack'd, malloc'd or %s%s\n",
442 xpre, a,
443 mc ? "(recently) free'd" : "on a free list",
444 xpost );
446 break;
448 case Addr_Stack:
449 VG_(emit)( "%sAddress 0x%lx is on thread %s%u's stack%s\n",
450 xpre, a,
451 opt_tnr_prefix (ai->Addr.Stack.tinfo),
452 tnr_else_tid (ai->Addr.Stack.tinfo),
453 xpost );
454 if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) {
455 const HChar *fn;
456 Bool hasfn;
457 const HChar *file;
458 Bool hasfile;
459 UInt linenum;
460 Bool haslinenum;
461 PtrdiffT offset;
463 if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.epoch,
464 ai->Addr.Stack.IP,
465 &offset))
466 haslinenum = VG_(get_linenum) (ai->Addr.Stack.epoch,
467 ai->Addr.Stack.IP - offset,
468 &linenum);
469 else
470 haslinenum = False;
472 hasfile = VG_(get_filename)(ai->Addr.Stack.epoch,
473 ai->Addr.Stack.IP, &file);
475 HChar strlinenum[16] = ""; // large enough
476 if (hasfile && haslinenum)
477 VG_(sprintf)(strlinenum, "%u", linenum);
479 hasfn = VG_(get_fnname)(ai->Addr.Stack.epoch,
480 ai->Addr.Stack.IP, &fn);
482 if (hasfn || hasfile)
483 VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n",
484 xpre,
485 ai->Addr.Stack.frameNo,
486 hasfn ? fn : "???",
487 hasfile ? file : "???", strlinenum,
488 xpost );
490 switch (ai->Addr.Stack.stackPos) {
491 case StackPos_stacked: break; // nothing more to say
493 case StackPos_below_stack_ptr:
494 case StackPos_guard_page:
495 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
496 xpre,
497 ai->Addr.Stack.stackPos == StackPos_guard_page ?
498 "In stack guard protected page, " : "",
499 - ai->Addr.Stack.spoffset,
500 xpost);
501 // Note: we change the sign of spoffset as the message speaks
502 // about the nr of bytes below stack pointer.
503 break;
505 default: vg_assert(0);
507 break;
509 case Addr_Block: {
510 SizeT block_szB = ai->Addr.Block.block_szB;
511 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
512 SizeT delta;
513 const HChar* relative;
515 if (rwoffset < 0) {
516 delta = (SizeT)(-rwoffset);
517 relative = "before";
518 } else if (rwoffset >= block_szB) {
519 delta = rwoffset - block_szB;
520 relative = "after";
521 } else {
522 delta = rwoffset;
523 relative = "inside";
525 if (is_arena_BlockKind (ai->Addr.Block.block_kind))
526 VG_(emit)(
527 "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
528 " in arena \"%s\"%s\n",
529 xpre,
530 a, delta,
531 relative,
532 ai->Addr.Block.block_kind==Block_ClientArenaMallocd
533 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
534 ? "" : "n unallocated",
535 block_szB,
536 ai->Addr.Block.block_desc, // arena name
537 xpost
539 else
540 VG_(emit)(
541 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
542 xpre,
543 a, delta,
544 relative,
545 ai->Addr.Block.block_desc,
546 block_szB,
547 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
548 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
549 : "client-defined",
550 xpost
552 if (ai->Addr.Block.block_kind==Block_Mallocd) {
553 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
554 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
556 else if (ai->Addr.Block.block_kind==Block_Freed) {
557 VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
558 if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
559 VG_(emit)(
560 "%sBlock was alloc'd at%s\n",
561 xpre,
562 xpost
564 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
567 else if (ai->Addr.Block.block_kind==Block_MempoolChunk
568 || ai->Addr.Block.block_kind==Block_UserG) {
569 // client-defined
570 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
571 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
572 /* Nb: cannot have a freed_at, as a freed client-defined block
573 has a Block_Freed block_kind. */
574 } else {
575 // Client or Valgrind arena. At least currently, we never
576 // have stacktraces for these.
577 vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
578 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
580 if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
581 VG_(emit)(
582 "%sBlock was alloc'd by thread %s%u%s\n",
583 xpre,
584 opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
585 tnr_else_tid (ai->Addr.Block.alloc_tinfo),
586 xpost
588 break;
591 case Addr_DataSym:
592 VG_(emit)( "%sAddress 0x%lx is %llu bytes "
593 "inside data symbol \"%ps\"%s\n",
594 xpre, a,
595 (ULong)ai->Addr.DataSym.offset,
596 ai->Addr.DataSym.name,
597 xpost );
598 break;
600 case Addr_Variable:
601 /* Note, no need for XML tags here, because descr1/2 will
602 already have <auxwhat> or <xauxwhat>s on them, in XML
603 mode. */
604 if (ai->Addr.Variable.descr1)
605 VG_(emit)( "%s%s\n",
606 VG_(clo_xml) ? " " : " ",
607 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
608 if (ai->Addr.Variable.descr2)
609 VG_(emit)( "%s%s\n",
610 VG_(clo_xml) ? " " : " ",
611 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
612 break;
614 case Addr_SectKind:
615 VG_(emit)( "%sAddress 0x%lx is in the %ps segment of %ps%s\n",
616 xpre, a,
617 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
618 ai->Addr.SectKind.objname,
619 xpost );
620 if (ai->Addr.SectKind.kind == Vg_SectText) {
621 /* To better describe the address in a text segment,
622 pp a dummy stacktrace made of this single address. */
623 VG_(pp_StackTrace)( VG_(current_DiEpoch)(), &a, 1 );
625 break;
627 case Addr_BrkSegment:
628 if (a < ai->Addr.BrkSegment.brk_limit)
629 VG_(emit)( "%sAddress 0x%lx is in the brk data segment"
630 " 0x%lx-0x%lx%s\n",
631 xpre, a,
632 VG_(brk_base),
633 ai->Addr.BrkSegment.brk_limit - 1,
634 xpost );
635 else
636 VG_(emit)( "%sAddress 0x%lx is %lu bytes after "
637 "the brk data segment limit"
638 " 0x%lx%s\n",
639 xpre, a,
640 a - ai->Addr.BrkSegment.brk_limit,
641 ai->Addr.BrkSegment.brk_limit,
642 xpost );
643 break;
645 case Addr_SegmentKind:
646 VG_(emit)( "%sAddress 0x%lx is in "
647 "a %s%s%s %s%s%ps segment%s\n",
648 xpre,
650 ai->Addr.SegmentKind.hasR ? "r" : "-",
651 ai->Addr.SegmentKind.hasW ? "w" : "-",
652 ai->Addr.SegmentKind.hasX ? "x" : "-",
653 pp_SegKind(ai->Addr.SegmentKind.segkind),
654 ai->Addr.SegmentKind.filename ?
655 " " : "",
656 ai->Addr.SegmentKind.filename ?
657 ai->Addr.SegmentKind.filename : "",
658 xpost );
659 break;
661 default:
662 VG_(core_panic)("mc_pp_AddrInfo");
666 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
668 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
671 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
673 pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
677 /*--------------------------------------------------------------------*/
678 /*--- end m_addrinfo.c ---*/
679 /*--------------------------------------------------------------------*/