Home | History | Annotate | Download | only in coregrind
      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 (at) 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. */
     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 
     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 
    312 void VG_(initThreadInfo) (ThreadInfo *tinfo)
    313 {
    314    tinfo->tid = 0;
    315    tinfo->tnr = 0;
    316 }
    317 
    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 
    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 
    383 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
    384 {
    385    if (tinfo.tnr != 0)
    386       return "#";
    387    else
    388       return "";
    389 }
    390 
    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 
    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 
    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 
    649 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
    650 {
    651    pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
    652 }
    653 
    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