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_libcassert.h"
34#include "pub_core_libcbase.h"
35#include "pub_core_libcprint.h"
36#include "pub_core_xarray.h"
37#include "pub_core_debuginfo.h"
38#include "pub_core_execontext.h"
39#include "pub_core_addrinfo.h"
40#include "pub_core_mallocfree.h"
41#include "pub_core_machine.h"
42#include "pub_core_options.h"
43
44void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
45{
46   ThreadId   tid;
47   Addr       stack_min, stack_max;
48   VgSectKind sect;
49
50   /* -- Perhaps the variable type/location data describes it? -- */
51   ai->Addr.Variable.descr1
52      = VG_(newXA)( VG_(malloc), "mc.da.descr1",
53                    VG_(free), sizeof(HChar) );
54   ai->Addr.Variable.descr2
55      = VG_(newXA)( VG_(malloc), "mc.da.descr2",
56                    VG_(free), sizeof(HChar) );
57
58   (void) VG_(get_data_description)( ai->Addr.Variable.descr1,
59                                     ai->Addr.Variable.descr2, a );
60   /* If there's nothing in descr1/2, free them.  Why is it safe to to
61      VG_(indexXA) at zero here?  Because VG_(get_data_description)
62      guarantees to zero terminate descr1/2 regardless of the outcome
63      of the call.  So there's always at least one element in each XA
64      after the call.
65   */
66   if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr1, 0 ))) {
67      VG_(deleteXA)( ai->Addr.Variable.descr1 );
68      ai->Addr.Variable.descr1 = NULL;
69   }
70   if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
71      VG_(deleteXA)( ai->Addr.Variable.descr2 );
72      ai->Addr.Variable.descr2 = NULL;
73   }
74   /* Assume (assert) that VG_(get_data_description) fills in descr1
75      before it fills in descr2 */
76   if (ai->Addr.Variable.descr1 == NULL)
77      vg_assert(ai->Addr.Variable.descr2 == NULL);
78   /* So did we get lucky? */
79   if (ai->Addr.Variable.descr1 != NULL) {
80      ai->tag = Addr_Variable;
81      return;
82   }
83   /* -- Have a look at the low level data symbols - perhaps it's in
84      there. -- */
85   VG_(memset)( &ai->Addr.DataSym.name,
86                0, sizeof(ai->Addr.DataSym.name));
87   if (VG_(get_datasym_and_offset)(
88             a, &ai->Addr.DataSym.name[0],
89             sizeof(ai->Addr.DataSym.name)-1,
90             &ai->Addr.DataSym.offset )) {
91      ai->tag = Addr_DataSym;
92      vg_assert( ai->Addr.DataSym.name
93                    [ sizeof(ai->Addr.DataSym.name)-1 ] == 0);
94      return;
95   }
96   /* -- Perhaps it's on a thread's stack? -- */
97   VG_(thread_stack_reset_iter)(&tid);
98   while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
99      if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
100         ai->tag            = Addr_Stack;
101         ai->Addr.Stack.tid = tid;
102         return;
103      }
104   }
105
106   /* -- Maybe it is in one of the m_mallocfree.c arenas. --  */
107   {
108      AddrArenaInfo aai;
109      VG_(describe_arena_addr) ( a, &aai );
110      if (aai.name != NULL) {
111         ai->tag = Addr_Block;
112         if (aai.aid == VG_AR_CLIENT)
113            ai->Addr.Block.block_kind
114               = aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd;
115         else
116            ai->Addr.Block.block_kind
117               = aai.free
118                  ? Block_ValgrindArenaFree :  Block_ValgrindArenaMallocd;
119         ai->Addr.Block.block_desc = aai.name;
120         ai->Addr.Block.block_szB = aai.block_szB;
121         ai->Addr.Block.rwoffset = aai.rwoffset;
122         ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
123         ai->Addr.Block.freed_at = VG_(null_ExeContext)();
124         return;
125      }
126   }
127
128   /* -- last ditch attempt at classification -- */
129   vg_assert( sizeof(ai->Addr.SectKind.objname) > 4 );
130   VG_(memset)( &ai->Addr.SectKind.objname,
131                0, sizeof(ai->Addr.SectKind.objname));
132   VG_(strcpy)( ai->Addr.SectKind.objname, "???" );
133   sect = VG_(DebugInfo_sect_kind)( &ai->Addr.SectKind.objname[0],
134                                    sizeof(ai->Addr.SectKind.objname)-1, a);
135   if (sect != Vg_SectUnknown) {
136      ai->tag = Addr_SectKind;
137      ai->Addr.SectKind.kind = sect;
138      vg_assert( ai->Addr.SectKind.objname
139                    [ sizeof(ai->Addr.SectKind.objname)-1 ] == 0);
140      return;
141   }
142   /* -- Clueless ... -- */
143   ai->tag = Addr_Unknown;
144   return;
145}
146
147void VG_(clear_addrinfo) ( AddrInfo* ai)
148{
149   switch (ai->tag) {
150      case Addr_Unknown:
151          break;
152
153      case Addr_Stack:
154          break;
155
156      case Addr_Block:
157         break;
158
159      case Addr_DataSym:
160         break;
161
162      case Addr_Variable:
163         if (ai->Addr.Variable.descr1 != NULL) {
164            VG_(deleteXA)( ai->Addr.Variable.descr1 );
165            ai->Addr.Variable.descr1 = NULL;
166         }
167         if (ai->Addr.Variable.descr2 != NULL) {
168            VG_(deleteXA)( ai->Addr.Variable.descr2 );
169            ai->Addr.Variable.descr2 = NULL;
170         }
171         break;
172
173      case Addr_SectKind:
174         break;
175
176      default:
177         VG_(core_panic)("VG_(clear_addrinfo)");
178   }
179
180   ai->tag = Addr_Undescribed;
181}
182
183static Bool is_arena_BlockKind(BlockKind bk)
184{
185   switch (bk) {
186      case Block_Mallocd:
187      case Block_Freed:
188      case Block_MempoolChunk:
189      case Block_UserG:                return False;
190
191      case Block_ClientArenaMallocd:
192      case Block_ClientArenaFree:
193      case Block_ValgrindArenaMallocd:
194      case Block_ValgrindArenaFree:    return True;
195
196      default:                         vg_assert (0);
197   }
198}
199
200static void pp_addrinfo_WRK ( Addr a, AddrInfo* ai, Bool mc, Bool maybe_gcc )
201{
202   const HChar* xpre  = VG_(clo_xml) ? "  <auxwhat>" : " ";
203   const HChar* xpost = VG_(clo_xml) ? "</auxwhat>"  : "";
204
205   vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
206
207   switch (ai->tag) {
208      case Addr_Unknown:
209         if (maybe_gcc) {
210            VG_(emit)( "%sAddress 0x%llx is just below the stack ptr.  "
211                       "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
212                       xpre, (ULong)a, xpost );
213	 } else {
214            VG_(emit)( "%sAddress 0x%llx "
215                       "is not stack'd, malloc'd or %s%s\n",
216                       xpre,
217                       (ULong)a,
218                       mc ? "(recently) free'd" : "on a free list",
219                       xpost );
220         }
221         break;
222
223      case Addr_Stack:
224         VG_(emit)( "%sAddress 0x%llx is on thread %d's stack%s\n",
225                    xpre, (ULong)a, ai->Addr.Stack.tid, xpost );
226         break;
227
228      case Addr_Block: {
229         SizeT    block_szB = ai->Addr.Block.block_szB;
230         PtrdiffT rwoffset  = ai->Addr.Block.rwoffset;
231         SizeT    delta;
232         const    HChar* relative;
233
234         if (rwoffset < 0) {
235            delta    = (SizeT)(-rwoffset);
236            relative = "before";
237         } else if (rwoffset >= block_szB) {
238            delta    = rwoffset - block_szB;
239            relative = "after";
240         } else {
241            delta    = rwoffset;
242            relative = "inside";
243         }
244         if (is_arena_BlockKind (ai->Addr.Block.block_kind))
245            VG_(emit)(
246               "%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
247               " in arena \"%s\"%s\n",
248               xpre,
249               a, delta,
250               relative,
251               ai->Addr.Block.block_kind==Block_ClientArenaMallocd
252                 || ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
253                 ? "" : "n unallocated",
254               block_szB,
255               ai->Addr.Block.block_desc,  // arena name
256               xpost
257            );
258         else
259            VG_(emit)(
260               "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
261               xpre,
262               a, delta,
263               relative,
264               ai->Addr.Block.block_desc,
265               block_szB,
266               ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
267               : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
268                                                        : "client-defined",
269               xpost
270            );
271         if (ai->Addr.Block.block_kind==Block_Mallocd) {
272            VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
273            tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
274         }
275         else if (ai->Addr.Block.block_kind==Block_Freed) {
276            VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
277            if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
278               VG_(emit)(
279                  "%s block was alloc'd at%s\n",
280                  xpre,
281                  xpost
282               );
283               VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
284            }
285         }
286         else if (ai->Addr.Block.block_kind==Block_MempoolChunk
287                  || ai->Addr.Block.block_kind==Block_UserG) {
288            // client-defined
289            VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
290            tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
291            /* Nb: cannot have a freed_at, as a freed client-defined block
292               has a Block_Freed block_kind. */
293         } else {
294            // Client or Valgrind arena. At least currently, we never
295            // have stacktraces for these.
296            tl_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
297            tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
298         }
299
300         break;
301      }
302
303      case Addr_DataSym:
304         VG_(emit)( "%sAddress 0x%llx is %llu bytes "
305                    "inside data symbol \"%pS\"%s\n",
306                    xpre,
307                    (ULong)a,
308                    (ULong)ai->Addr.DataSym.offset,
309                    ai->Addr.DataSym.name,
310                    xpost );
311         break;
312
313      case Addr_Variable:
314         /* Note, no need for XML tags here, because descr1/2 will
315            already have <auxwhat> or <xauxwhat>s on them, in XML
316            mode. */
317         if (ai->Addr.Variable.descr1)
318            VG_(emit)( "%s%s\n",
319                       VG_(clo_xml) ? "  " : " ",
320                       (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
321         if (ai->Addr.Variable.descr2)
322            VG_(emit)( "%s%s\n",
323                       VG_(clo_xml) ? "  " : " ",
324                       (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
325         break;
326
327      case Addr_SectKind:
328         VG_(emit)( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
329                    xpre,
330                    (ULong)a,
331                    VG_(pp_SectKind)(ai->Addr.SectKind.kind),
332                    ai->Addr.SectKind.objname,
333                    xpost );
334         break;
335
336      default:
337         VG_(tool_panic)("mc_pp_AddrInfo");
338   }
339}
340
341void VG_(pp_addrinfo) ( Addr a, AddrInfo* ai )
342{
343   pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
344}
345
346void VG_(pp_addrinfo_mc) ( Addr a, AddrInfo* ai, Bool maybe_gcc )
347{
348   pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
349}
350
351
352/*--------------------------------------------------------------------*/
353/*--- end                                             m_addrinfo.c ---*/
354/*--------------------------------------------------------------------*/
355