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-2013 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 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 
    308 void VG_(initThreadInfo) (ThreadInfo *tinfo)
    309 {
    310    tinfo->tid = 0;
    311    tinfo->tnr = 0;
    312 }
    313 
    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 
    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 
    379 static const HChar* opt_tnr_prefix (ThreadInfo tinfo)
    380 {
    381    if (tinfo.tnr != 0)
    382       return "#";
    383    else
    384       return "";
    385 }
    386 
    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 
    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 
    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 
    650 void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai )
    651 {
    652    pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
    653 }
    654 
    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