• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2017 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
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 overridden 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 #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;
288       }
289 
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;
304       }
305    }
306 
307    /* -- Clueless ... -- */
308    ai->tag = Addr_Unknown;
309    return;
310 }
311 
VG_(initThreadInfo)312 void VG_(initThreadInfo) (ThreadInfo *tinfo)
313 {
314    tinfo->tid = 0;
315    tinfo->tnr = 0;
316 }
317 
VG_(clear_addrinfo)318 void VG_(clear_addrinfo) ( AddrInfo* ai)
319 {
320    switch (ai->tag) {
321       case Addr_Undescribed:
322          break;
323 
324       case Addr_Unknown:
325          break;
326 
327       case Addr_Stack:
328          break;
329 
330       case Addr_Block:
331          break;
332 
333       case Addr_DataSym:
334          VG_(free)(ai->Addr.DataSym.name);
335          break;
336 
337       case Addr_Variable:
338          if (ai->Addr.Variable.descr1 != NULL) {
339             VG_(deleteXA)( ai->Addr.Variable.descr1 );
340             ai->Addr.Variable.descr1 = NULL;
341          }
342          if (ai->Addr.Variable.descr2 != NULL) {
343             VG_(deleteXA)( ai->Addr.Variable.descr2 );
344             ai->Addr.Variable.descr2 = NULL;
345          }
346          break;
347 
348       case Addr_SectKind:
349          VG_(free)(ai->Addr.SectKind.objname);
350          break;
351 
352       case Addr_BrkSegment:
353          break;
354 
355       case Addr_SegmentKind:
356          VG_(free)(ai->Addr.SegmentKind.filename);
357          break;
358 
359       default:
360          VG_(core_panic)("VG_(clear_addrinfo)");
361    }
362 
363    ai->tag = Addr_Undescribed;
364 }
365 
is_arena_BlockKind(BlockKind bk)366 static Bool is_arena_BlockKind(BlockKind bk)
367 {
368    switch (bk) {
369       case Block_Mallocd:
370       case Block_Freed:
371       case Block_MempoolChunk:
372       case Block_UserG:                return False;
373 
374       case Block_ClientArenaMallocd:
375       case Block_ClientArenaFree:
376       case Block_ValgrindArenaMallocd:
377       case Block_ValgrindArenaFree:    return True;
378 
379       default:                         vg_assert (0);
380    }
381 }
382 
opt_tnr_prefix(ThreadInfo tinfo)383 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
384 {
385    if (tinfo.tnr != 0)
386       return "#";
387    else
388       return "";
389 }
390 
tnr_else_tid(ThreadInfo tinfo)391 static UInt tnr_else_tid (ThreadInfo tinfo)
392 {
393    if (tinfo.tnr != 0)
394       return tinfo.tnr;
395    else
396       return tinfo.tid;
397 }
398 
pp_SegKind(SegKind sk)399 static const HChar* pp_SegKind ( SegKind sk )
400 {
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);
406    }
407 }
408 
pp_addrinfo_WRK(Addr a,const AddrInfo * ai,Bool mc,Bool maybe_gcc)409 static void pp_addrinfo_WRK ( Addr a, const AddrInfo* ai, Bool mc,
410                               Bool maybe_gcc )
411 {
412    const HChar* xpre  = VG_(clo_xml) ? "  <auxwhat>" : " ";
413    const HChar* xpost = VG_(clo_xml) ? "</auxwhat>"  : "";
414 
415    vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
416 
417    switch (ai->tag) {
418       case Addr_Undescribed:
419          VG_(core_panic)("mc_pp_AddrInfo Addr_Undescribed");
420 
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 );
432          }
433          break;
434 
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;
449 
450             if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP,
451                                                   &offset))
452                haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset,
453                                               &linenum);
454             else
455                haslinenum = False;
456 
457             hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file);
458 
459             HChar strlinenum[16] = "";   // large enough
460             if (hasfile && haslinenum)
461                VG_(sprintf)(strlinenum, "%u", linenum);
462 
463             hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn);
464 
465             if (hasfn || hasfile)
466                VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n",
467                           xpre,
468                           ai->Addr.Stack.frameNo,
469                           hasfn ? fn : "???",
470                           hasfile ? file : "???", strlinenum,
471                           xpost );
472          }
473          switch (ai->Addr.Stack.stackPos) {
474             case StackPos_stacked: break; // nothing more to say
475 
476             case StackPos_below_stack_ptr:
477             case StackPos_guard_page:
478                 VG_(emit)("%s%s%ld bytes below stack pointer%s\n",
479                           xpre,
480                           ai->Addr.Stack.stackPos == StackPos_guard_page ?
481                           "In stack guard protected page, " : "",
482                           - ai->Addr.Stack.spoffset,
483                           xpost);
484                 // Note: we change the sign of spoffset as the message speaks
485                 // about the nr of bytes below stack pointer.
486                 break;
487 
488             default: vg_assert(0);
489          }
490          break;
491 
492       case Addr_Block: {
493          SizeT    block_szB = ai->Addr.Block.block_szB;
494          PtrdiffT rwoffset  = ai->Addr.Block.rwoffset;
495          SizeT    delta;
496          const    HChar* relative;
497 
498          if (rwoffset < 0) {
499             delta    = (SizeT)(-rwoffset);
500             relative = "before";
501          } else if (rwoffset >= block_szB) {
502             delta    = rwoffset - block_szB;
503             relative = "after";
504          } else {
505             delta    = rwoffset;
506             relative = "inside";
507          }
508          if (is_arena_BlockKind (ai->Addr.Block.block_kind))
509             VG_(emit)(
510                "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
511                " in arena \"%s\"%s\n",
512                xpre,
513                a, delta,
514                relative,
515                ai->Addr.Block.block_kind==Block_ClientArenaMallocd
516                  || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
517                  ? "" : "n unallocated",
518                block_szB,
519                ai->Addr.Block.block_desc,  // arena name
520                xpost
521             );
522          else
523             VG_(emit)(
524                "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
525                xpre,
526                a, delta,
527                relative,
528                ai->Addr.Block.block_desc,
529                block_szB,
530                ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
531                : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
532                                                         : "client-defined",
533                xpost
534             );
535          if (ai->Addr.Block.block_kind==Block_Mallocd) {
536             VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
537             vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
538          }
539          else if (ai->Addr.Block.block_kind==Block_Freed) {
540             VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
541             if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
542                VG_(emit)(
543                   "%sBlock was alloc'd at%s\n",
544                   xpre,
545                   xpost
546                );
547                VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
548             }
549          }
550          else if (ai->Addr.Block.block_kind==Block_MempoolChunk
551                   || ai->Addr.Block.block_kind==Block_UserG) {
552             // client-defined
553             VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
554             vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
555             /* Nb: cannot have a freed_at, as a freed client-defined block
556                has a Block_Freed block_kind. */
557          } else {
558             // Client or Valgrind arena. At least currently, we never
559             // have stacktraces for these.
560             vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
561             vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
562          }
563          if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
564             VG_(emit)(
565                "%sBlock was alloc'd by thread %s%u%s\n",
566                xpre,
567                opt_tnr_prefix (ai->Addr.Block.alloc_tinfo),
568                tnr_else_tid (ai->Addr.Block.alloc_tinfo),
569                xpost
570             );
571          break;
572       }
573 
574       case Addr_DataSym:
575          VG_(emit)( "%sAddress 0x%lx is %llu bytes "
576                     "inside data symbol \"%ps\"%s\n",
577                     xpre, a,
578                     (ULong)ai->Addr.DataSym.offset,
579                     ai->Addr.DataSym.name,
580                     xpost );
581          break;
582 
583       case Addr_Variable:
584          /* Note, no need for XML tags here, because descr1/2 will
585             already have <auxwhat> or <xauxwhat>s on them, in XML
586             mode. */
587          if (ai->Addr.Variable.descr1)
588             VG_(emit)( "%s%s\n",
589                        VG_(clo_xml) ? "  " : " ",
590                        (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
591          if (ai->Addr.Variable.descr2)
592             VG_(emit)( "%s%s\n",
593                        VG_(clo_xml) ? "  " : " ",
594                        (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
595          break;
596 
597       case Addr_SectKind:
598          VG_(emit)( "%sAddress 0x%lx is in the %ps segment of %ps%s\n",
599                     xpre, a,
600                     VG_(pp_SectKind)(ai->Addr.SectKind.kind),
601                     ai->Addr.SectKind.objname,
602                     xpost );
603          if (ai->Addr.SectKind.kind == Vg_SectText) {
604             /* To better describe the address in a text segment,
605                pp a dummy stacktrace made of this single address. */
606             VG_(pp_StackTrace)( &a, 1 );
607          }
608          break;
609 
610       case Addr_BrkSegment:
611          if (a < ai->Addr.BrkSegment.brk_limit)
612             VG_(emit)( "%sAddress 0x%lx is in the brk data segment"
613                        " 0x%lx-0x%lx%s\n",
614                        xpre, a,
615                        VG_(brk_base),
616                        ai->Addr.BrkSegment.brk_limit - 1,
617                        xpost );
618          else
619             VG_(emit)( "%sAddress 0x%lx is %lu bytes after "
620                        "the brk data segment limit"
621                        " 0x%lx%s\n",
622                        xpre, a,
623                        a - ai->Addr.BrkSegment.brk_limit,
624                        ai->Addr.BrkSegment.brk_limit,
625                        xpost );
626          break;
627 
628       case Addr_SegmentKind:
629          VG_(emit)( "%sAddress 0x%lx is in "
630                     "a %s%s%s %s%s%ps segment%s\n",
631                     xpre,
632                     a,
633                     ai->Addr.SegmentKind.hasR ? "r" : "-",
634                     ai->Addr.SegmentKind.hasW ? "w" : "-",
635                     ai->Addr.SegmentKind.hasX ? "x" : "-",
636                     pp_SegKind(ai->Addr.SegmentKind.segkind),
637                     ai->Addr.SegmentKind.filename ?
638                     " " : "",
639                     ai->Addr.SegmentKind.filename ?
640                     ai->Addr.SegmentKind.filename : "",
641                     xpost );
642          break;
643 
644       default:
645          VG_(core_panic)("mc_pp_AddrInfo");
646    }
647 }
648 
VG_(pp_addrinfo)649 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
650 {
651    pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
652 }
653 
VG_(pp_addrinfo_mc)654 void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc )
655 {
656    pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
657 }
658 
659 
660 /*--------------------------------------------------------------------*/
661 /*--- end                                             m_addrinfo.c ---*/
662 /*--------------------------------------------------------------------*/
663