1
2 /*--------------------------------------------------------------------*/
3 /*--- Obtaining information about an address. ---*/
4 /*--- m_addrinfo.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright (C) 2008-2013 OpenWorks Ltd
12 info@open-works.co.uk
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 #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"
48
49 /* Returns the tid whose stack includes the address a.
50 If not found, returns VG_INVALID_THREADID. */
find_tid_with_stack_containing(Addr a)51 static ThreadId find_tid_with_stack_containing (Addr a)
52 {
53 ThreadId tid;
54 Addr start, end;
55
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;
63 }
64
65 /* Stack limits found. Search the tid to which this stack belongs. */
66 vg_assert (start <= a);
67 vg_assert (a <= end);
68
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) ... */
72 {
73 Addr stack_min, stack_max;
74
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;
79 }
80 }
81
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;
87 }
88
VG_(describe_addr)89 void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
90 {
91 VgSectKind sect;
92
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) );
100
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 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.
108 */
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;
112 }
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;
116 }
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;
125 }
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;
135 }
136 /* -- Perhaps it's on a thread's stack? -- */
137 {
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;
147
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;
176 }
177 }
178 return;
179 }
180 }
181 }
182
183 /* -- Maybe it is in one of the m_mallocfree.c arenas. -- */
184 {
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;
203 }
204 }
205
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;
213 }
214
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). */
221 {
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.
226
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;
244 }
245 }
246
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;
258 }
259 }
260
261 /* -- and yet another last ditch attempt at classification -- */
262 /* Try to find a segment belonging to the client. */
263 {
264 const NSegment *seg = VG_(am_find_nsegment) (a);
265
266 /* Special case to detect the brk data segment. */
267 if (seg != NULL
268 && seg->kind == SkAnonC
269 && VG_(brk_limit) >= seg->start
270 && VG_(brk_limit) <= seg->end+1) {
271 /* Address a is in a Anon Client segment which contains
272 VG_(brk_limit). So, this segment is the brk data segment
273 as initimg-linux.c:setup_client_dataseg maps an anonymous
274 segment followed by a reservation, with one reservation
275 page that will never be used by syswrap-generic.c:do_brk,
276 when increasing VG_(brk_limit).
277 So, the brk data segment will never be merged with the
278 next segment, and so an address in that area will
279 either be in the brk data segment, or in the unmapped
280 part of the brk data segment reservation. */
281 ai->tag = Addr_BrkSegment;
282 ai->Addr.BrkSegment.brk_limit = VG_(brk_limit);
283 return;
284 }
285
286 if (seg != NULL
287 && (seg->kind == SkAnonC
288 || seg->kind == SkFileC
289 || seg->kind == SkShmC)) {
290 ai->tag = Addr_SegmentKind;
291 ai->Addr.SegmentKind.segkind = seg->kind;
292 ai->Addr.SegmentKind.filename = NULL;
293 if (seg->kind == SkFileC)
294 ai->Addr.SegmentKind.filename
295 = VG_(strdup)("mc.da.skfname", VG_(am_get_filename)(seg));
296 ai->Addr.SegmentKind.hasR = seg->hasR;
297 ai->Addr.SegmentKind.hasW = seg->hasW;
298 ai->Addr.SegmentKind.hasX = seg->hasX;
299 return;
300 }
301 }
302
303 /* -- Clueless ... -- */
304 ai->tag = Addr_Unknown;
305 return;
306 }
307
VG_(initThreadInfo)308 void VG_(initThreadInfo) (ThreadInfo *tinfo)
309 {
310 tinfo->tid = 0;
311 tinfo->tnr = 0;
312 }
313
VG_(clear_addrinfo)314 void VG_(clear_addrinfo) ( AddrInfo* ai)
315 {
316 switch (ai->tag) {
317 case Addr_Undescribed:
318 break;
319
320 case Addr_Unknown:
321 break;
322
323 case Addr_Stack:
324 break;
325
326 case Addr_Block:
327 break;
328
329 case Addr_DataSym:
330 VG_(free)(ai->Addr.DataSym.name);
331 break;
332
333 case Addr_Variable:
334 if (ai->Addr.Variable.descr1 != NULL) {
335 VG_(deleteXA)( ai->Addr.Variable.descr1 );
336 ai->Addr.Variable.descr1 = NULL;
337 }
338 if (ai->Addr.Variable.descr2 != NULL) {
339 VG_(deleteXA)( ai->Addr.Variable.descr2 );
340 ai->Addr.Variable.descr2 = NULL;
341 }
342 break;
343
344 case Addr_SectKind:
345 VG_(free)(ai->Addr.SectKind.objname);
346 break;
347
348 case Addr_BrkSegment:
349 break;
350
351 case Addr_SegmentKind:
352 VG_(free)(ai->Addr.SegmentKind.filename);
353 break;
354
355 default:
356 VG_(core_panic)("VG_(clear_addrinfo)");
357 }
358
359 ai->tag = Addr_Undescribed;
360 }
361
is_arena_BlockKind(BlockKind bk)362 static Bool is_arena_BlockKind(BlockKind bk)
363 {
364 switch (bk) {
365 case Block_Mallocd:
366 case Block_Freed:
367 case Block_MempoolChunk:
368 case Block_UserG: return False;
369
370 case Block_ClientArenaMallocd:
371 case Block_ClientArenaFree:
372 case Block_ValgrindArenaMallocd:
373 case Block_ValgrindArenaFree: return True;
374
375 default: vg_assert (0);
376 }
377 }
378
opt_tnr_prefix(ThreadInfo tinfo)379 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
380 {
381 if (tinfo.tnr != 0)
382 return "#";
383 else
384 return "";
385 }
386
tnr_else_tid(ThreadInfo tinfo)387 static UInt tnr_else_tid (ThreadInfo tinfo)
388 {
389 if (tinfo.tnr != 0)
390 return tinfo.tnr;
391 else
392 return tinfo.tid;
393 }
394
pp_SegKind(SegKind sk)395 static const HChar* pp_SegKind ( SegKind sk )
396 {
397 switch (sk) {
398 case SkAnonC: return "anonymous";
399 case SkFileC: return "mapped file";
400 case SkShmC: return "shared memory";
401 default: vg_assert(0);
402 }
403 }
404
pp_addrinfo_WRK(Addr a,const AddrInfo * ai,Bool mc,Bool maybe_gcc)405 static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc,
406 Bool maybe_gcc )
407 {
408 const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
409 const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
410
411 vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
412
413 switch (ai->tag) {
414 case Addr_Undescribed:
415 VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed");
416
417 case Addr_Unknown:
418 if (maybe_gcc) {
419 VG_(emit)( "%sAddress 0x%llx is just below the stack ptr. "
420 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
421 xpre, (ULong)a, xpost );
422 } else {
423 VG_(emit)( "%sAddress 0x%llx "
424 "is not stack'd, malloc'd or %s%s\n",
425 xpre,
426 (ULong)a,
427 mc ? "(recently) free'd" : "on a free list",
428 xpost );
429 }
430 break;
431
432 case Addr_Stack:
433 VG_(emit)( "%sAddress 0x%llx is on thread %s%d's stack%s\n",
434 xpre, (ULong)a,
435 opt_tnr_prefix (ai->Addr.Stack.tinfo),
436 tnr_else_tid (ai->Addr.Stack.tinfo),
437 xpost );
438 if (ai->Addr.Stack.frameNo != -1 && ai->Addr.Stack.IP != 0) {
439 const HChar *fn;
440 Bool hasfn;
441 const HChar *file;
442 Bool hasfile;
443 UInt linenum;
444 Bool haslinenum;
445 PtrdiffT offset;
446
447 if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP,
448 &offset))
449 haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset,
450 &linenum);
451 else
452 haslinenum = False;
453
454 hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file);
455
456 HChar strlinenum[16] = ""; // large enough
457 if (hasfile && haslinenum)
458 VG_(sprintf)(strlinenum, "%d", linenum);
459
460 hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn);
461
462 if (hasfn || hasfile)
463 VG_(emit)( "%sin frame #%d, created by %s (%s:%s)%s\n",
464 xpre,
465 ai->Addr.Stack.frameNo,
466 hasfn ? fn : "???",
467 hasfile ? file : "???", strlinenum,
468 xpost );
469 }
470 switch (ai->Addr.Stack.stackPos) {
471 case StackPos_stacked: break; // nothing more to say
472
473 case StackPos_below_stack_ptr:
474 case StackPos_guard_page:
475 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
476 xpre,
477 ai->Addr.Stack.stackPos == StackPos_guard_page ?
478 "In stack guard protected page, " : "",
479 - ai->Addr.Stack.spoffset,
480 xpost);
481 // Note: we change the sign of spoffset as the message speaks
482 // about the nr of bytes below stack pointer.
483 break;
484
485 default: vg_assert(0);
486 }
487 break;
488
489 case Addr_Block: {
490 SizeT block_szB = ai->Addr.Block.block_szB;
491 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
492 SizeT delta;
493 const HChar* relative;
494
495 if (rwoffset < 0) {
496 delta = (SizeT)(-rwoffset);
497 relative = "before";
498 } else if (rwoffset >= block_szB) {
499 delta = rwoffset - block_szB;
500 relative = "after";
501 } else {
502 delta = rwoffset;
503 relative = "inside";
504 }
505 if (is_arena_BlockKind (ai->Addr.Block.block_kind))
506 VG_(emit)(
507 "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
508 " in arena \"%s\"%s\n",
509 xpre,
510 a, delta,
511 relative,
512 ai->Addr.Block.block_kind==Block_ClientArenaMallocd
513 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
514 ? "" : "n unallocated",
515 block_szB,
516 ai->Addr.Block.block_desc, // arena name
517 xpost
518 );
519 else
520 VG_(emit)(
521 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
522 xpre,
523 a, delta,
524 relative,
525 ai->Addr.Block.block_desc,
526 block_szB,
527 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
528 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
529 : "client-defined",
530 xpost
531 );
532 if (ai->Addr.Block.block_kind==Block_Mallocd) {
533 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
534 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
535 }
536 else if (ai->Addr.Block.block_kind==Block_Freed) {
537 VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
538 if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
539 VG_(emit)(
540 "%sBlock was alloc'd at%s\n",
541 xpre,
542 xpost
543 );
544 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
545 }
546 }
547 else if (ai->Addr.Block.block_kind==Block_MempoolChunk
548 || ai->Addr.Block.block_kind==Block_UserG) {
549 // client-defined
550 VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
551 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
552 /* Nb: cannot have a freed_at, as a freed client-defined block
553 has a Block_Freed block_kind. */
554 } else {
555 // Client or Valgrind arena. At least currently, we never
556 // have stacktraces for these.
557 vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
558 vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
559 }
560 if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
561 VG_(emit)(
562 "%sBlock was alloc'd by thread %s%d%s\n",
563 xpre,
564 opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
565 tnr_else_tid (ai->Addr.Block.alloc_tinfo),
566 xpost
567 );
568 break;
569 }
570
571 case Addr_DataSym:
572 VG_(emit)( "%sAddress 0x%llx is %llu bytes "
573 "inside data symbol \"%pS\"%s\n",
574 xpre,
575 (ULong)a,
576 (ULong)ai->Addr.DataSym.offset,
577 ai->Addr.DataSym.name,
578 xpost );
579 break;
580
581 case Addr_Variable:
582 /* Note, no need for XML tags here, because descr1/2 will
583 already have <auxwhat> or <xauxwhat>s on them, in XML
584 mode. */
585 if (ai->Addr.Variable.descr1)
586 VG_(emit)( "%s%s\n",
587 VG_(clo_xml) ? " " : " ",
588 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
589 if (ai->Addr.Variable.descr2)
590 VG_(emit)( "%s%s\n",
591 VG_(clo_xml) ? " " : " ",
592 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
593 break;
594
595 case Addr_SectKind:
596 VG_(emit)( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
597 xpre,
598 (ULong)a,
599 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
600 ai->Addr.SectKind.objname,
601 xpost );
602 if (ai->Addr.SectKind.kind == Vg_SectText) {
603 /* To better describe the address in a text segment,
604 pp a dummy stacktrace made of this single address. */
605 VG_(pp_StackTrace)( &a, 1 );
606 }
607 break;
608
609 case Addr_BrkSegment:
610 if (a < ai->Addr.BrkSegment.brk_limit)
611 VG_(emit)( "%sAddress 0x%llx is in the brk data segment"
612 " 0x%llx-0x%llx%s\n",
613 xpre,
614 (ULong)a,
615 (ULong)VG_(brk_base),
616 (ULong)ai->Addr.BrkSegment.brk_limit - 1,
617 xpost );
618 else
619 VG_(emit)( "%sAddress 0x%llx is %lu bytes after "
620 "the brk data segment limit"
621 " 0x%llx%s\n",
622 xpre,
623 (ULong)a,
624 a - ai->Addr.BrkSegment.brk_limit,
625 (ULong)ai->Addr.BrkSegment.brk_limit,
626 xpost );
627 break;
628
629 case Addr_SegmentKind:
630 VG_(emit)( "%sAddress 0x%llx is in "
631 "a %s%s%s %s%s%pS segment%s\n",
632 xpre,
633 (ULong)a,
634 ai->Addr.SegmentKind.hasR ? "r" : "-",
635 ai->Addr.SegmentKind.hasW ? "w" : "-",
636 ai->Addr.SegmentKind.hasX ? "x" : "-",
637 pp_SegKind(ai->Addr.SegmentKind.segkind),
638 ai->Addr.SegmentKind.filename ?
639 " " : "",
640 ai->Addr.SegmentKind.filename ?
641 ai->Addr.SegmentKind.filename : "",
642 xpost );
643 break;
644
645 default:
646 VG_(core_panic)("mc_pp_AddrInfo");
647 }
648 }
649
VG_(pp_addrinfo)650 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
651 {
652 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
653 }
654
VG_(pp_addrinfo_mc)655 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
656 {
657 pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
658 }
659
660
661 /*--------------------------------------------------------------------*/
662 /*--- end m_addrinfo.c ---*/
663 /*--------------------------------------------------------------------*/
664