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
VG_(describe_addr)44 void 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
VG_(clear_addrinfo)147 void 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
is_arena_BlockKind(BlockKind bk)183 static 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
pp_addrinfo_WRK(Addr a,AddrInfo * ai,Bool mc,Bool maybe_gcc)200 static 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
VG_(pp_addrinfo)341 void VG_(pp_addrinfo) ( Addr a, AddrInfo* ai )
342 {
343 pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
344 }
345
VG_(pp_addrinfo_mc)346 void 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