blob: 36d3595125d5559fa289bb8740695a677f3f9f77 [file] [log] [blame]
sewardj7ce71662008-05-02 10:33:15 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management, printing, etc, of errors and suppressions. ---*/
4/*--- mc_errors.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of MemCheck, a heavyweight Valgrind tool for
9 detecting memory errors.
10
sewardj9eecbbb2010-05-03 21:37:12 +000011 Copyright (C) 2000-2010 Julian Seward
sewardj7ce71662008-05-02 10:33:15 +000012 jseward@acm.org
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_tool_basics.h"
sewardj3b290482011-05-06 21:02:55 +000033#include "pub_tool_gdbserver.h"
sewardj7ce71662008-05-02 10:33:15 +000034#include "pub_tool_hashtable.h" // For mc_include.h
35#include "pub_tool_libcbase.h"
36#include "pub_tool_libcassert.h"
37#include "pub_tool_libcprint.h"
38#include "pub_tool_machine.h"
39#include "pub_tool_mallocfree.h"
40#include "pub_tool_options.h"
sewardj7ce71662008-05-02 10:33:15 +000041#include "pub_tool_replacemalloc.h"
42#include "pub_tool_tooliface.h"
43#include "pub_tool_threadstate.h"
sewardj7ce71662008-05-02 10:33:15 +000044#include "pub_tool_debuginfo.h" // VG_(get_dataname_and_offset)
sewardj6b523cd2009-07-15 14:49:40 +000045#include "pub_tool_xarray.h"
sewardj7ce71662008-05-02 10:33:15 +000046
47#include "mc_include.h"
sewardj7ce71662008-05-02 10:33:15 +000048
49
50/*------------------------------------------------------------*/
51/*--- Error types ---*/
52/*------------------------------------------------------------*/
53
54/* See comment in mc_include.h */
55Bool MC_(any_value_errors) = False;
56
57
58// Different kinds of blocks.
59typedef enum {
60 Block_Mallocd = 111,
61 Block_Freed,
62 Block_Mempool,
63 Block_MempoolChunk,
64 Block_UserG
65} BlockKind;
66
67/* ------------------ Addresses -------------------- */
68
69/* The classification of a faulting address. */
70typedef
71 enum {
72 Addr_Undescribed, // as-yet unclassified
73 Addr_Unknown, // classification yielded nothing useful
74 Addr_Block, // in malloc'd/free'd block
75 Addr_Stack, // on a thread's stack
76 Addr_DataSym, // in a global data sym
77 Addr_Variable, // variable described by the debug info
78 Addr_SectKind // last-ditch classification attempt
79 }
80 AddrTag;
81
82typedef
83 struct _AddrInfo
84 AddrInfo;
85
86struct _AddrInfo {
87 AddrTag tag;
88 union {
89 // As-yet unclassified.
90 struct { } Undescribed;
91
92 // On a stack.
93 struct {
94 ThreadId tid; // Which thread's stack?
95 } Stack;
96
97 // This covers heap blocks (normal and from mempools) and user-defined
98 // blocks.
99 struct {
100 BlockKind block_kind;
101 Char* block_desc; // "block", "mempool" or user-defined
102 SizeT block_szB;
njnc4431bf2009-01-15 21:29:24 +0000103 PtrdiffT rwoffset;
sewardj7ce71662008-05-02 10:33:15 +0000104 ExeContext* lastchange;
105 } Block;
106
njnc4431bf2009-01-15 21:29:24 +0000107 // In a global .data symbol. This holds the first 127 chars of
108 // the variable's name (zero terminated), plus a (memory) offset.
sewardj7ce71662008-05-02 10:33:15 +0000109 struct {
njnc4431bf2009-01-15 21:29:24 +0000110 Char name[128];
111 PtrdiffT offset;
sewardj7ce71662008-05-02 10:33:15 +0000112 } DataSym;
113
sewardj6b523cd2009-07-15 14:49:40 +0000114 // Is described by Dwarf debug info. XArray*s of HChar.
sewardj7ce71662008-05-02 10:33:15 +0000115 struct {
sewardj6b523cd2009-07-15 14:49:40 +0000116 XArray* /* of HChar */ descr1;
117 XArray* /* of HChar */ descr2;
sewardj7ce71662008-05-02 10:33:15 +0000118 } Variable;
119
120 // Could only narrow it down to be the PLT/GOT/etc of a given
121 // object. Better than nothing, perhaps.
122 struct {
123 Char objname[128];
124 VgSectKind kind;
125 } SectKind;
126
127 // Classification yielded nothing useful.
128 struct { } Unknown;
129
130 } Addr;
131};
132
133/* ------------------ Errors ----------------------- */
134
135/* What kind of error it is. */
136typedef
137 enum {
138 Err_Value,
139 Err_Cond,
140 Err_CoreMem,
141 Err_Addr,
142 Err_Jump,
143 Err_RegParam,
144 Err_MemParam,
145 Err_User,
146 Err_Free,
147 Err_FreeMismatch,
148 Err_Overlap,
149 Err_Leak,
150 Err_IllegalMempool,
151 }
152 MC_ErrorTag;
153
154
155typedef struct _MC_Error MC_Error;
156
157struct _MC_Error {
158 // Nb: we don't need the tag here, as it's stored in the Error type! Yuk.
159 //MC_ErrorTag tag;
160
161 union {
162 // Use of an undefined value:
163 // - as a pointer in a load or store
164 // - as a jump target
165 struct {
166 SizeT szB; // size of value in bytes
167 // Origin info
168 UInt otag; // origin tag
169 ExeContext* origin_ec; // filled in later
170 } Value;
171
172 // Use of an undefined value in a conditional branch or move.
173 struct {
174 // Origin info
175 UInt otag; // origin tag
176 ExeContext* origin_ec; // filled in later
177 } Cond;
178
179 // Addressability error in core (signal-handling) operation.
180 // It would be good to get rid of this error kind, merge it with
181 // another one somehow.
182 struct {
183 } CoreMem;
184
185 // Use of an unaddressable memory location in a load or store.
186 struct {
187 Bool isWrite; // read or write?
188 SizeT szB; // not used for exec (jump) errors
189 Bool maybe_gcc; // True if just below %esp -- could be a gcc bug
190 AddrInfo ai;
191 } Addr;
192
193 // Jump to an unaddressable memory location.
194 struct {
195 AddrInfo ai;
196 } Jump;
197
198 // System call register input contains undefined bytes.
199 struct {
200 // Origin info
201 UInt otag; // origin tag
202 ExeContext* origin_ec; // filled in later
203 } RegParam;
204
205 // System call memory input contains undefined/unaddressable bytes
206 struct {
207 Bool isAddrErr; // Addressability or definedness error?
208 AddrInfo ai;
209 // Origin info
210 UInt otag; // origin tag
211 ExeContext* origin_ec; // filled in later
212 } MemParam;
213
214 // Problem found from a client request like CHECK_MEM_IS_ADDRESSABLE.
215 struct {
216 Bool isAddrErr; // Addressability or definedness error?
217 AddrInfo ai;
218 // Origin info
219 UInt otag; // origin tag
220 ExeContext* origin_ec; // filled in later
221 } User;
222
223 // Program tried to free() something that's not a heap block (this
224 // covers double-frees). */
225 struct {
226 AddrInfo ai;
227 } Free;
228
229 // Program allocates heap block with one function
230 // (malloc/new/new[]/custom) and deallocates with not the matching one.
231 struct {
232 AddrInfo ai;
233 } FreeMismatch;
234
235 // Call to strcpy, memcpy, etc, with overlapping blocks.
236 struct {
237 Addr src; // Source block
238 Addr dst; // Destination block
239 Int szB; // Size in bytes; 0 if unused.
240 } Overlap;
241
242 // A memory leak.
243 struct {
244 UInt n_this_record;
245 UInt n_total_records;
njnb7a4e2e2009-05-01 00:30:43 +0000246 LossRecord* lr;
sewardj7ce71662008-05-02 10:33:15 +0000247 } Leak;
248
249 // A memory pool error.
250 struct {
251 AddrInfo ai;
252 } IllegalMempool;
253
254 } Err;
255};
256
257
258/*------------------------------------------------------------*/
259/*--- Printing errors ---*/
260/*------------------------------------------------------------*/
261
sewardj6b523cd2009-07-15 14:49:40 +0000262/* This is the "this error is due to be printed shortly; so have a
263 look at it any print any preamble you want" function. Which, in
264 Memcheck, we don't use. Hence a no-op.
265*/
266void MC_(before_pp_Error) ( Error* err ) {
267}
268
269/* Do a printf-style operation on either the XML or normal output
270 channel, depending on the setting of VG_(clo_xml).
271*/
272static void emit_WRK ( HChar* format, va_list vargs )
273{
274 if (VG_(clo_xml)) {
275 VG_(vprintf_xml)(format, vargs);
276 } else {
277 VG_(vmessage)(Vg_UserMsg, format, vargs);
278 }
279}
280static void emit ( HChar* format, ... ) PRINTF_CHECK(1, 2);
281static void emit ( HChar* format, ... )
282{
283 va_list vargs;
284 va_start(vargs, format);
285 emit_WRK(format, vargs);
286 va_end(vargs);
287}
288static void emiN ( HChar* format, ... ) /* NO FORMAT CHECK */
289{
290 va_list vargs;
291 va_start(vargs, format);
292 emit_WRK(format, vargs);
293 va_end(vargs);
294}
295
296
sewardj7ce71662008-05-02 10:33:15 +0000297static void mc_pp_AddrInfo ( Addr a, AddrInfo* ai, Bool maybe_gcc )
298{
299 HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
300 HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
301
302 switch (ai->tag) {
303 case Addr_Unknown:
304 if (maybe_gcc) {
sewardj6b523cd2009-07-15 14:49:40 +0000305 emit( "%sAddress 0x%llx is just below the stack ptr. "
306 "To suppress, use: --workaround-gcc296-bugs=yes%s\n",
307 xpre, (ULong)a, xpost );
sewardj7ce71662008-05-02 10:33:15 +0000308 } else {
sewardj6b523cd2009-07-15 14:49:40 +0000309 emit( "%sAddress 0x%llx "
310 "is not stack'd, malloc'd or (recently) free'd%s\n",
311 xpre, (ULong)a, xpost );
sewardj7ce71662008-05-02 10:33:15 +0000312 }
313 break;
314
315 case Addr_Stack:
sewardj6b523cd2009-07-15 14:49:40 +0000316 emit( "%sAddress 0x%llx is on thread %d's stack%s\n",
317 xpre, (ULong)a, ai->Addr.Stack.tid, xpost );
sewardj7ce71662008-05-02 10:33:15 +0000318 break;
319
320 case Addr_Block: {
njnc4431bf2009-01-15 21:29:24 +0000321 SizeT block_szB = ai->Addr.Block.block_szB;
322 PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
323 SizeT delta;
324 const Char* relative;
sewardj7ce71662008-05-02 10:33:15 +0000325
326 if (rwoffset < 0) {
327 delta = (SizeT)(-rwoffset);
328 relative = "before";
329 } else if (rwoffset >= block_szB) {
330 delta = rwoffset - block_szB;
331 relative = "after";
332 } else {
333 delta = rwoffset;
334 relative = "inside";
335 }
sewardj6b523cd2009-07-15 14:49:40 +0000336 emit(
337 "%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
sewardj7ce71662008-05-02 10:33:15 +0000338 xpre,
339 a, delta, relative, ai->Addr.Block.block_desc,
340 block_szB,
341 ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
342 : ai->Addr.Block.block_kind==Block_Freed ? "free'd"
343 : "client-defined",
sewardj6b523cd2009-07-15 14:49:40 +0000344 xpost
345 );
sewardj7ce71662008-05-02 10:33:15 +0000346 VG_(pp_ExeContext)(ai->Addr.Block.lastchange);
347 break;
348 }
349
350 case Addr_DataSym:
sewardj6b523cd2009-07-15 14:49:40 +0000351 emiN( "%sAddress 0x%llx is %llu bytes "
bartb3af9cf2011-10-06 19:08:37 +0000352 "inside data symbol \"%pS\"%s\n",
sewardj6b523cd2009-07-15 14:49:40 +0000353 xpre,
354 (ULong)a,
355 (ULong)ai->Addr.DataSym.offset,
356 ai->Addr.DataSym.name,
357 xpost );
sewardj7ce71662008-05-02 10:33:15 +0000358 break;
359
360 case Addr_Variable:
sewardj6b523cd2009-07-15 14:49:40 +0000361 /* Note, no need for XML tags here, because descr1/2 will
362 already have <auxwhat> or <xauxwhat>s on them, in XML
363 mode. */
364 if (ai->Addr.Variable.descr1)
365 emit( "%s%s\n",
366 VG_(clo_xml) ? " " : " ",
367 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
368 if (ai->Addr.Variable.descr2)
369 emit( "%s%s\n",
370 VG_(clo_xml) ? " " : " ",
371 (HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
sewardj7ce71662008-05-02 10:33:15 +0000372 break;
373
374 case Addr_SectKind:
bartb3af9cf2011-10-06 19:08:37 +0000375 emiN( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
sewardj6b523cd2009-07-15 14:49:40 +0000376 xpre,
377 (ULong)a,
378 VG_(pp_SectKind)(ai->Addr.SectKind.kind),
379 ai->Addr.SectKind.objname,
380 xpost );
sewardj7ce71662008-05-02 10:33:15 +0000381 break;
382
383 default:
384 VG_(tool_panic)("mc_pp_AddrInfo");
385 }
386}
387
388static const HChar* str_leak_lossmode ( Reachedness lossmode )
389{
390 const HChar *loss = "?";
391 switch (lossmode) {
392 case Unreached: loss = "definitely lost"; break;
393 case IndirectLeak: loss = "indirectly lost"; break;
njn8225cc02009-03-09 22:52:24 +0000394 case Possible: loss = "possibly lost"; break;
395 case Reachable: loss = "still reachable"; break;
sewardj7ce71662008-05-02 10:33:15 +0000396 }
397 return loss;
398}
399
400static const HChar* xml_leak_kind ( Reachedness lossmode )
401{
402 const HChar *loss = "?";
403 switch (lossmode) {
404 case Unreached: loss = "Leak_DefinitelyLost"; break;
405 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
njn8225cc02009-03-09 22:52:24 +0000406 case Possible: loss = "Leak_PossiblyLost"; break;
407 case Reachable: loss = "Leak_StillReachable"; break;
sewardj7ce71662008-05-02 10:33:15 +0000408 }
409 return loss;
410}
411
sewardj7ce71662008-05-02 10:33:15 +0000412static void mc_pp_origin ( ExeContext* ec, UInt okind )
413{
sewardj6b523cd2009-07-15 14:49:40 +0000414 HChar* src = NULL;
sewardj7ce71662008-05-02 10:33:15 +0000415 tl_assert(ec);
416
417 switch (okind) {
418 case MC_OKIND_STACK: src = " by a stack allocation"; break;
419 case MC_OKIND_HEAP: src = " by a heap allocation"; break;
420 case MC_OKIND_USER: src = " by a client request"; break;
421 case MC_OKIND_UNKNOWN: src = ""; break;
422 }
423 tl_assert(src); /* guards against invalid 'okind' */
424
425 if (VG_(clo_xml)) {
sewardj6b523cd2009-07-15 14:49:40 +0000426 emit( " <auxwhat>Uninitialised value was created%s</auxwhat>\n",
427 src);
428 VG_(pp_ExeContext)( ec );
429 } else {
430 emit( " Uninitialised value was created%s\n", src);
431 VG_(pp_ExeContext)( ec );
sewardj7ce71662008-05-02 10:33:15 +0000432 }
433}
434
sewardjc8bd1df2011-06-26 12:41:33 +0000435char * MC_(snprintf_delta) (char * buf, Int size,
436 SizeT current_val, SizeT old_val,
437 LeakCheckDeltaMode delta_mode)
438{
439 if (delta_mode == LCD_Any)
440 buf[0] = '\0';
441 else if (current_val >= old_val)
442 VG_(snprintf) (buf, size, " (+%'lu)", current_val - old_val);
443 else
444 VG_(snprintf) (buf, size, " (-%'lu)", old_val - current_val);
445
446 return buf;
447}
448
sewardj7ce71662008-05-02 10:33:15 +0000449void MC_(pp_Error) ( Error* err )
450{
sewardj6b523cd2009-07-15 14:49:40 +0000451 const Bool xml = VG_(clo_xml); /* a shorthand */
sewardj7ce71662008-05-02 10:33:15 +0000452 MC_Error* extra = VG_(get_error_extra)(err);
453
454 switch (VG_(get_error_kind)(err)) {
sewardj6b523cd2009-07-15 14:49:40 +0000455 case Err_CoreMem:
sewardj7ce71662008-05-02 10:33:15 +0000456 /* What the hell *is* a CoreMemError? jrs 2005-May-18 */
457 /* As of 2006-Dec-14, it's caused by unaddressable bytes in a
458 signal handler frame. --njn */
sewardj6b523cd2009-07-15 14:49:40 +0000459 // JRS 17 May 09: None of our regtests exercise this; hence AFAIK
460 // the following code is untested. Bad.
461 if (xml) {
462 emit( " <kind>CoreMemError</kind>\n" );
bartb3af9cf2011-10-06 19:08:37 +0000463 emiN( " <what>%pS contains unaddressable byte(s)</what>\n",
sewardj6b523cd2009-07-15 14:49:40 +0000464 VG_(get_error_string)(err));
465 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
466 } else {
467 emit( "%s contains unaddressable byte(s)\n",
468 VG_(get_error_string)(err));
469 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
470 }
sewardj7ce71662008-05-02 10:33:15 +0000471 break;
sewardj7ce71662008-05-02 10:33:15 +0000472
473 case Err_Value:
474 MC_(any_value_errors) = True;
sewardj6b523cd2009-07-15 14:49:40 +0000475 if (xml) {
476 emit( " <kind>UninitValue</kind>\n" );
477 emit( " <what>Use of uninitialised value of size %ld</what>\n",
478 extra->Err.Value.szB );
479 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
480 if (extra->Err.Value.origin_ec)
481 mc_pp_origin( extra->Err.Value.origin_ec,
482 extra->Err.Value.otag & 3 );
sewardj7ce71662008-05-02 10:33:15 +0000483 } else {
sewardj6b523cd2009-07-15 14:49:40 +0000484 /* Could also show extra->Err.Cond.otag if debugging origin
485 tracking */
486 emit( "Use of uninitialised value of size %ld\n",
487 extra->Err.Value.szB );
488 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
489 if (extra->Err.Value.origin_ec)
490 mc_pp_origin( extra->Err.Value.origin_ec,
491 extra->Err.Value.otag & 3 );
sewardj7ce71662008-05-02 10:33:15 +0000492 }
sewardj7ce71662008-05-02 10:33:15 +0000493 break;
494
495 case Err_Cond:
496 MC_(any_value_errors) = True;
sewardj6b523cd2009-07-15 14:49:40 +0000497 if (xml) {
498 emit( " <kind>UninitCondition</kind>\n" );
499 emit( " <what>Conditional jump or move depends"
500 " on uninitialised value(s)</what>\n" );
501 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
502 if (extra->Err.Cond.origin_ec)
503 mc_pp_origin( extra->Err.Cond.origin_ec,
504 extra->Err.Cond.otag & 3 );
sewardj7ce71662008-05-02 10:33:15 +0000505 } else {
sewardj6b523cd2009-07-15 14:49:40 +0000506 /* Could also show extra->Err.Cond.otag if debugging origin
507 tracking */
508 emit( "Conditional jump or move depends"
509 " on uninitialised value(s)\n" );
510 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
511 if (extra->Err.Cond.origin_ec)
512 mc_pp_origin( extra->Err.Cond.origin_ec,
513 extra->Err.Cond.otag & 3 );
sewardj7ce71662008-05-02 10:33:15 +0000514 }
sewardj7ce71662008-05-02 10:33:15 +0000515 break;
516
517 case Err_RegParam:
518 MC_(any_value_errors) = True;
sewardj6b523cd2009-07-15 14:49:40 +0000519 if (xml) {
520 emit( " <kind>SyscallParam</kind>\n" );
bartb3af9cf2011-10-06 19:08:37 +0000521 emiN( " <what>Syscall param %pS contains "
sewardj6b523cd2009-07-15 14:49:40 +0000522 "uninitialised byte(s)</what>\n",
523 VG_(get_error_string)(err) );
524 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
525 if (extra->Err.RegParam.origin_ec)
526 mc_pp_origin( extra->Err.RegParam.origin_ec,
527 extra->Err.RegParam.otag & 3 );
528 } else {
529 emit( "Syscall param %s contains uninitialised byte(s)\n",
530 VG_(get_error_string)(err) );
531 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
532 if (extra->Err.RegParam.origin_ec)
533 mc_pp_origin( extra->Err.RegParam.origin_ec,
534 extra->Err.RegParam.otag & 3 );
535 }
sewardj7ce71662008-05-02 10:33:15 +0000536 break;
537
538 case Err_MemParam:
539 if (!extra->Err.MemParam.isAddrErr)
540 MC_(any_value_errors) = True;
sewardj6b523cd2009-07-15 14:49:40 +0000541 if (xml) {
542 emit( " <kind>SyscallParam</kind>\n" );
bartb3af9cf2011-10-06 19:08:37 +0000543 emiN( " <what>Syscall param %pS points to %s byte(s)</what>\n",
sewardj6b523cd2009-07-15 14:49:40 +0000544 VG_(get_error_string)(err),
545 extra->Err.MemParam.isAddrErr
546 ? "unaddressable" : "uninitialised" );
547 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
548 mc_pp_AddrInfo(VG_(get_error_address)(err),
549 &extra->Err.MemParam.ai, False);
550 if (extra->Err.MemParam.origin_ec
551 && !extra->Err.MemParam.isAddrErr)
552 mc_pp_origin( extra->Err.MemParam.origin_ec,
553 extra->Err.MemParam.otag & 3 );
554 } else {
555 emit( "Syscall param %s points to %s byte(s)\n",
556 VG_(get_error_string)(err),
557 extra->Err.MemParam.isAddrErr
558 ? "unaddressable" : "uninitialised" );
559 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
560 mc_pp_AddrInfo(VG_(get_error_address)(err),
561 &extra->Err.MemParam.ai, False);
562 if (extra->Err.MemParam.origin_ec
563 && !extra->Err.MemParam.isAddrErr)
564 mc_pp_origin( extra->Err.MemParam.origin_ec,
565 extra->Err.MemParam.otag & 3 );
566 }
sewardj7ce71662008-05-02 10:33:15 +0000567 break;
568
569 case Err_User:
570 if (!extra->Err.User.isAddrErr)
571 MC_(any_value_errors) = True;
sewardj6b523cd2009-07-15 14:49:40 +0000572 if (xml) {
573 emit( " <kind>ClientCheck</kind>\n" );
574 emit( " <what>%s byte(s) found "
575 "during client check request</what>\n",
576 extra->Err.User.isAddrErr
577 ? "Unaddressable" : "Uninitialised" );
578 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
579 mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.User.ai,
580 False);
581 if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
582 mc_pp_origin( extra->Err.User.origin_ec,
583 extra->Err.User.otag & 3 );
584 } else {
585 emit( "%s byte(s) found during client check request\n",
586 extra->Err.User.isAddrErr
587 ? "Unaddressable" : "Uninitialised" );
588 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
589 mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.User.ai,
590 False);
591 if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
592 mc_pp_origin( extra->Err.User.origin_ec,
593 extra->Err.User.otag & 3 );
594 }
sewardj7ce71662008-05-02 10:33:15 +0000595 break;
596
597 case Err_Free:
sewardj6b523cd2009-07-15 14:49:40 +0000598 if (xml) {
599 emit( " <kind>InvalidFree</kind>\n" );
bart91347382011-03-25 20:07:25 +0000600 emit( " <what>Invalid free() / delete / delete[]"
601 " / realloc()</what>\n" );
sewardj6b523cd2009-07-15 14:49:40 +0000602 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
603 mc_pp_AddrInfo( VG_(get_error_address)(err),
604 &extra->Err.Free.ai, False );
605 } else {
bart91347382011-03-25 20:07:25 +0000606 emit( "Invalid free() / delete / delete[] / realloc()\n" );
sewardj6b523cd2009-07-15 14:49:40 +0000607 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
608 mc_pp_AddrInfo( VG_(get_error_address)(err),
609 &extra->Err.Free.ai, False );
610 }
sewardj7ce71662008-05-02 10:33:15 +0000611 break;
612
613 case Err_FreeMismatch:
sewardj6b523cd2009-07-15 14:49:40 +0000614 if (xml) {
615 emit( " <kind>MismatchedFree</kind>\n" );
616 emit( " <what>Mismatched free() / delete / delete []</what>\n" );
617 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
618 mc_pp_AddrInfo(VG_(get_error_address)(err),
619 &extra->Err.FreeMismatch.ai, False);
620 } else {
621 emit( "Mismatched free() / delete / delete []\n" );
622 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
623 mc_pp_AddrInfo(VG_(get_error_address)(err),
624 &extra->Err.FreeMismatch.ai, False);
625 }
sewardj7ce71662008-05-02 10:33:15 +0000626 break;
627
628 case Err_Addr:
sewardj6b523cd2009-07-15 14:49:40 +0000629 if (xml) {
630 emit( " <kind>Invalid%s</kind>\n",
631 extra->Err.Addr.isWrite ? "Write" : "Read" );
632 emit( " <what>Invalid %s of size %ld</what>\n",
633 extra->Err.Addr.isWrite ? "write" : "read",
634 extra->Err.Addr.szB );
635 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
636 mc_pp_AddrInfo( VG_(get_error_address)(err),
637 &extra->Err.Addr.ai,
638 extra->Err.Addr.maybe_gcc );
sewardj7ce71662008-05-02 10:33:15 +0000639 } else {
sewardj6b523cd2009-07-15 14:49:40 +0000640 emit( "Invalid %s of size %ld\n",
641 extra->Err.Addr.isWrite ? "write" : "read",
642 extra->Err.Addr.szB );
643 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
644
645 mc_pp_AddrInfo( VG_(get_error_address)(err),
646 &extra->Err.Addr.ai,
647 extra->Err.Addr.maybe_gcc );
sewardj7ce71662008-05-02 10:33:15 +0000648 }
sewardj7ce71662008-05-02 10:33:15 +0000649 break;
650
651 case Err_Jump:
sewardj6b523cd2009-07-15 14:49:40 +0000652 if (xml) {
653 emit( " <kind>InvalidJump</kind>\n" );
654 emit( " <what>Jump to the invalid address stated "
655 "on the next line</what>\n" );
656 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
657 mc_pp_AddrInfo( VG_(get_error_address)(err), &extra->Err.Jump.ai,
658 False );
659 } else {
660 emit( "Jump to the invalid address stated on the next line\n" );
661 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
662 mc_pp_AddrInfo( VG_(get_error_address)(err), &extra->Err.Jump.ai,
663 False );
664 }
sewardj7ce71662008-05-02 10:33:15 +0000665 break;
666
667 case Err_Overlap:
sewardj6b523cd2009-07-15 14:49:40 +0000668 if (xml) {
669 emit( " <kind>Overlap</kind>\n" );
670 if (extra->Err.Overlap.szB == 0) {
671 emiN( " <what>Source and destination overlap "
bartb3af9cf2011-10-06 19:08:37 +0000672 "in %pS(%#lx, %#lx)\n</what>\n",
sewardj6b523cd2009-07-15 14:49:40 +0000673 VG_(get_error_string)(err),
674 extra->Err.Overlap.dst, extra->Err.Overlap.src );
675 } else {
676 emit( " <what>Source and destination overlap "
677 "in %s(%#lx, %#lx, %d)</what>\n",
678 VG_(get_error_string)(err),
679 extra->Err.Overlap.dst, extra->Err.Overlap.src,
680 extra->Err.Overlap.szB );
681 }
682 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
683 } else {
684 if (extra->Err.Overlap.szB == 0) {
bartb3af9cf2011-10-06 19:08:37 +0000685 emiN( "Source and destination overlap in %pS(%#lx, %#lx)\n",
sewardj6b523cd2009-07-15 14:49:40 +0000686 VG_(get_error_string)(err),
687 extra->Err.Overlap.dst, extra->Err.Overlap.src );
688 } else {
689 emit( "Source and destination overlap in %s(%#lx, %#lx, %d)\n",
690 VG_(get_error_string)(err),
691 extra->Err.Overlap.dst, extra->Err.Overlap.src,
692 extra->Err.Overlap.szB );
693 }
694 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
695 }
sewardj7ce71662008-05-02 10:33:15 +0000696 break;
697
698 case Err_IllegalMempool:
sewardj6b523cd2009-07-15 14:49:40 +0000699 // JRS 17 May 09: None of our regtests exercise this; hence AFAIK
700 // the following code is untested. Bad.
701 if (xml) {
702 emit( " <kind>InvalidMemPool</kind>\n" );
703 emit( " <what>Illegal memory pool address</what>\n" );
704 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
705 mc_pp_AddrInfo( VG_(get_error_address)(err),
706 &extra->Err.IllegalMempool.ai, False );
707 } else {
708 emit( "Illegal memory pool address\n" );
709 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
710 mc_pp_AddrInfo( VG_(get_error_address)(err),
711 &extra->Err.IllegalMempool.ai, False );
712 }
sewardj7ce71662008-05-02 10:33:15 +0000713 break;
714
715 case Err_Leak: {
sewardj7ce71662008-05-02 10:33:15 +0000716 UInt n_this_record = extra->Err.Leak.n_this_record;
717 UInt n_total_records = extra->Err.Leak.n_total_records;
njnb7a4e2e2009-05-01 00:30:43 +0000718 LossRecord* lr = extra->Err.Leak.lr;
sewardjc8bd1df2011-06-26 12:41:33 +0000719 // char arrays to produce the indication of increase/decrease in case
sewardj30b3eca2011-06-28 08:20:39 +0000720 // of delta_mode != LCD_Any
sewardjc8bd1df2011-06-26 12:41:33 +0000721 char d_bytes[20];
722 char d_direct_bytes[20];
723 char d_indirect_bytes[20];
724 char d_num_blocks[20];
725
726 MC_(snprintf_delta) (d_bytes, 20,
727 lr->szB + lr->indirect_szB,
728 lr->old_szB + lr->old_indirect_szB,
729 MC_(detect_memory_leaks_last_delta_mode));
730 MC_(snprintf_delta) (d_direct_bytes, 20,
731 lr->szB,
732 lr->old_szB,
733 MC_(detect_memory_leaks_last_delta_mode));
734 MC_(snprintf_delta) (d_indirect_bytes, 20,
735 lr->indirect_szB,
736 lr->old_indirect_szB,
737 MC_(detect_memory_leaks_last_delta_mode));
738 MC_(snprintf_delta) (d_num_blocks, 20,
739 (SizeT) lr->num_blocks,
740 (SizeT) lr->old_num_blocks,
741 MC_(detect_memory_leaks_last_delta_mode));
742
sewardj6b523cd2009-07-15 14:49:40 +0000743 if (xml) {
744 emit(" <kind>%s</kind>\n", xml_leak_kind(lr->key.state));
745 if (lr->indirect_szB > 0) {
746 emit( " <xwhat>\n" );
sewardjc8bd1df2011-06-26 12:41:33 +0000747 emit( " <text>%'lu%s (%'lu%s direct, %'lu%s indirect) bytes "
748 "in %'u%s blocks"
sewardj6b523cd2009-07-15 14:49:40 +0000749 " are %s in loss record %'u of %'u</text>\n",
sewardjc8bd1df2011-06-26 12:41:33 +0000750 lr->szB + lr->indirect_szB, d_bytes,
751 lr->szB, d_direct_bytes,
752 lr->indirect_szB, d_indirect_bytes,
753 lr->num_blocks, d_num_blocks,
sewardj6b523cd2009-07-15 14:49:40 +0000754 str_leak_lossmode(lr->key.state),
755 n_this_record, n_total_records );
sewardj7ce71662008-05-02 10:33:15 +0000756 // Nb: don't put commas in these XML numbers
sewardj6b523cd2009-07-15 14:49:40 +0000757 emit( " <leakedbytes>%lu</leakedbytes>\n",
758 lr->szB + lr->indirect_szB );
759 emit( " <leakedblocks>%u</leakedblocks>\n", lr->num_blocks );
760 emit( " </xwhat>\n" );
761 } else {
762 emit( " <xwhat>\n" );
sewardjc8bd1df2011-06-26 12:41:33 +0000763 emit( " <text>%'lu%s bytes in %'u%s blocks"
sewardj6b523cd2009-07-15 14:49:40 +0000764 " are %s in loss record %'u of %'u</text>\n",
sewardjc8bd1df2011-06-26 12:41:33 +0000765 lr->szB, d_direct_bytes,
766 lr->num_blocks, d_num_blocks,
sewardj6b523cd2009-07-15 14:49:40 +0000767 str_leak_lossmode(lr->key.state),
768 n_this_record, n_total_records );
769 emit( " <leakedbytes>%ld</leakedbytes>\n", lr->szB);
770 emit( " <leakedblocks>%d</leakedblocks>\n", lr->num_blocks);
771 emit( " </xwhat>\n" );
sewardj7ce71662008-05-02 10:33:15 +0000772 }
sewardj6b523cd2009-07-15 14:49:40 +0000773 VG_(pp_ExeContext)(lr->key.allocated_at);
774 } else { /* ! if (xml) */
sewardj6b523cd2009-07-15 14:49:40 +0000775 if (lr->indirect_szB > 0) {
776 emit(
sewardjc8bd1df2011-06-26 12:41:33 +0000777 "%'lu%s (%'lu%s direct, %'lu%s indirect) bytes in %'u%s blocks"
sewardj6b523cd2009-07-15 14:49:40 +0000778 " are %s in loss record %'u of %'u\n",
sewardjc8bd1df2011-06-26 12:41:33 +0000779 lr->szB + lr->indirect_szB, d_bytes,
780 lr->szB, d_direct_bytes,
781 lr->indirect_szB, d_indirect_bytes,
782 lr->num_blocks, d_num_blocks,
783 str_leak_lossmode(lr->key.state),
sewardj6b523cd2009-07-15 14:49:40 +0000784 n_this_record, n_total_records
785 );
786 } else {
787 emit(
sewardjc8bd1df2011-06-26 12:41:33 +0000788 "%'lu%s bytes in %'u%s blocks are %s in loss record %'u of %'u\n",
789 lr->szB, d_direct_bytes,
790 lr->num_blocks, d_num_blocks,
791 str_leak_lossmode(lr->key.state),
sewardj6b523cd2009-07-15 14:49:40 +0000792 n_this_record, n_total_records
793 );
sewardj7ce71662008-05-02 10:33:15 +0000794 }
sewardj6b523cd2009-07-15 14:49:40 +0000795 VG_(pp_ExeContext)(lr->key.allocated_at);
796 } /* if (xml) */
sewardj7ce71662008-05-02 10:33:15 +0000797 break;
798 }
799
800 default:
801 VG_(printf)("Error:\n unknown Memcheck error code %d\n",
802 VG_(get_error_kind)(err));
803 VG_(tool_panic)("unknown error code in mc_pp_Error)");
804 }
805}
806
807/*------------------------------------------------------------*/
808/*--- Recording errors ---*/
809/*------------------------------------------------------------*/
810
811/* These many bytes below %ESP are considered addressible if we're
812 doing the --workaround-gcc296-bugs hack. */
813#define VG_GCC296_BUG_STACK_SLOP 1024
814
815/* Is this address within some small distance below %ESP? Used only
816 for the --workaround-gcc296-bugs kludge. */
817static Bool is_just_below_ESP( Addr esp, Addr aa )
818{
sewardj7d751b22010-07-21 12:46:44 +0000819 esp -= VG_STACK_REDZONE_SZB;
sewardj7ce71662008-05-02 10:33:15 +0000820 if (esp > aa && (esp - aa) <= VG_GCC296_BUG_STACK_SLOP)
821 return True;
822 else
823 return False;
824}
825
826/* --- Called from generated and non-generated code --- */
827
828void MC_(record_address_error) ( ThreadId tid, Addr a, Int szB,
829 Bool isWrite )
830{
831 MC_Error extra;
832 Bool just_below_esp;
833
834 if (MC_(in_ignored_range)(a))
835 return;
836
sewardj3b290482011-05-06 21:02:55 +0000837 if (VG_(is_watched)( (isWrite ? write_watchpoint : read_watchpoint), a, szB))
838 return;
839
sewardj7ce71662008-05-02 10:33:15 +0000840 just_below_esp = is_just_below_ESP( VG_(get_SP)(tid), a );
841
842 /* If this is caused by an access immediately below %ESP, and the
843 user asks nicely, we just ignore it. */
844 if (MC_(clo_workaround_gcc296_bugs) && just_below_esp)
845 return;
846
847 extra.Err.Addr.isWrite = isWrite;
848 extra.Err.Addr.szB = szB;
849 extra.Err.Addr.maybe_gcc = just_below_esp;
850 extra.Err.Addr.ai.tag = Addr_Undescribed;
851 VG_(maybe_record_error)( tid, Err_Addr, a, /*s*/NULL, &extra );
852}
853
854void MC_(record_value_error) ( ThreadId tid, Int szB, UInt otag )
855{
856 MC_Error extra;
857 tl_assert( MC_(clo_mc_level) >= 2 );
858 if (otag > 0)
859 tl_assert( MC_(clo_mc_level) == 3 );
860 extra.Err.Value.szB = szB;
861 extra.Err.Value.otag = otag;
862 extra.Err.Value.origin_ec = NULL; /* Filled in later */
863 VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra );
864}
865
866void MC_(record_cond_error) ( ThreadId tid, UInt otag )
867{
868 MC_Error extra;
869 tl_assert( MC_(clo_mc_level) >= 2 );
870 if (otag > 0)
871 tl_assert( MC_(clo_mc_level) == 3 );
872 extra.Err.Cond.otag = otag;
873 extra.Err.Cond.origin_ec = NULL; /* Filled in later */
874 VG_(maybe_record_error)( tid, Err_Cond, /*addr*/0, /*s*/NULL, &extra );
875}
876
877/* --- Called from non-generated code --- */
878
njn1dcee092009-02-24 03:07:37 +0000879/* This is for memory errors in signal-related memory. */
880void MC_(record_core_mem_error) ( ThreadId tid, Char* msg )
sewardj7ce71662008-05-02 10:33:15 +0000881{
882 VG_(maybe_record_error)( tid, Err_CoreMem, /*addr*/0, msg, /*extra*/NULL );
883}
884
885void MC_(record_regparam_error) ( ThreadId tid, Char* msg, UInt otag )
886{
887 MC_Error extra;
888 tl_assert(VG_INVALID_THREADID != tid);
889 if (otag > 0)
890 tl_assert( MC_(clo_mc_level) == 3 );
891 extra.Err.RegParam.otag = otag;
892 extra.Err.RegParam.origin_ec = NULL; /* Filled in later */
893 VG_(maybe_record_error)( tid, Err_RegParam, /*addr*/0, msg, &extra );
894}
895
896void MC_(record_memparam_error) ( ThreadId tid, Addr a,
897 Bool isAddrErr, Char* msg, UInt otag )
898{
899 MC_Error extra;
900 tl_assert(VG_INVALID_THREADID != tid);
901 if (!isAddrErr)
902 tl_assert( MC_(clo_mc_level) >= 2 );
903 if (otag != 0) {
904 tl_assert( MC_(clo_mc_level) == 3 );
905 tl_assert( !isAddrErr );
906 }
907 extra.Err.MemParam.isAddrErr = isAddrErr;
908 extra.Err.MemParam.ai.tag = Addr_Undescribed;
909 extra.Err.MemParam.otag = otag;
910 extra.Err.MemParam.origin_ec = NULL; /* Filled in later */
911 VG_(maybe_record_error)( tid, Err_MemParam, a, msg, &extra );
912}
913
914void MC_(record_jump_error) ( ThreadId tid, Addr a )
915{
916 MC_Error extra;
917 tl_assert(VG_INVALID_THREADID != tid);
918 extra.Err.Jump.ai.tag = Addr_Undescribed;
919 VG_(maybe_record_error)( tid, Err_Jump, a, /*s*/NULL, &extra );
920}
921
922void MC_(record_free_error) ( ThreadId tid, Addr a )
923{
924 MC_Error extra;
925 tl_assert(VG_INVALID_THREADID != tid);
926 extra.Err.Free.ai.tag = Addr_Undescribed;
927 VG_(maybe_record_error)( tid, Err_Free, a, /*s*/NULL, &extra );
928}
929
930void MC_(record_freemismatch_error) ( ThreadId tid, MC_Chunk* mc )
931{
932 MC_Error extra;
933 AddrInfo* ai = &extra.Err.FreeMismatch.ai;
934 tl_assert(VG_INVALID_THREADID != tid);
935 ai->tag = Addr_Block;
936 ai->Addr.Block.block_kind = Block_Mallocd; // Nb: Not 'Block_Freed'
937 ai->Addr.Block.block_desc = "block";
938 ai->Addr.Block.block_szB = mc->szB;
939 ai->Addr.Block.rwoffset = 0;
940 ai->Addr.Block.lastchange = mc->where;
941 VG_(maybe_record_error)( tid, Err_FreeMismatch, mc->data, /*s*/NULL,
942 &extra );
943}
944
945void MC_(record_illegal_mempool_error) ( ThreadId tid, Addr a )
946{
947 MC_Error extra;
948 tl_assert(VG_INVALID_THREADID != tid);
949 extra.Err.IllegalMempool.ai.tag = Addr_Undescribed;
950 VG_(maybe_record_error)( tid, Err_IllegalMempool, a, /*s*/NULL, &extra );
951}
952
953void MC_(record_overlap_error) ( ThreadId tid, Char* function,
954 Addr src, Addr dst, SizeT szB )
955{
956 MC_Error extra;
957 tl_assert(VG_INVALID_THREADID != tid);
958 extra.Err.Overlap.src = src;
959 extra.Err.Overlap.dst = dst;
960 extra.Err.Overlap.szB = szB;
961 VG_(maybe_record_error)(
962 tid, Err_Overlap, /*addr*/0, /*s*/function, &extra );
963}
964
965Bool MC_(record_leak_error) ( ThreadId tid, UInt n_this_record,
njnb7a4e2e2009-05-01 00:30:43 +0000966 UInt n_total_records, LossRecord* lr,
njn18afe5d2009-08-10 08:25:39 +0000967 Bool print_record, Bool count_error )
sewardj7ce71662008-05-02 10:33:15 +0000968{
969 MC_Error extra;
970 extra.Err.Leak.n_this_record = n_this_record;
971 extra.Err.Leak.n_total_records = n_total_records;
njnb7a4e2e2009-05-01 00:30:43 +0000972 extra.Err.Leak.lr = lr;
sewardj7ce71662008-05-02 10:33:15 +0000973 return
974 VG_(unique_error) ( tid, Err_Leak, /*Addr*/0, /*s*/NULL, &extra,
njn29a5c012009-05-06 06:15:55 +0000975 lr->key.allocated_at, print_record,
njn18afe5d2009-08-10 08:25:39 +0000976 /*allow_GDB_attach*/False, count_error );
sewardj7ce71662008-05-02 10:33:15 +0000977}
978
979void MC_(record_user_error) ( ThreadId tid, Addr a,
980 Bool isAddrErr, UInt otag )
981{
982 MC_Error extra;
983 if (otag != 0) {
984 tl_assert(!isAddrErr);
985 tl_assert( MC_(clo_mc_level) == 3 );
986 }
987 if (!isAddrErr) {
988 tl_assert( MC_(clo_mc_level) >= 2 );
989 }
990 tl_assert(VG_INVALID_THREADID != tid);
991 extra.Err.User.isAddrErr = isAddrErr;
992 extra.Err.User.ai.tag = Addr_Undescribed;
993 extra.Err.User.otag = otag;
994 extra.Err.User.origin_ec = NULL; /* Filled in later */
995 VG_(maybe_record_error)( tid, Err_User, a, /*s*/NULL, &extra );
996}
997
998/*------------------------------------------------------------*/
999/*--- Other error operations ---*/
1000/*------------------------------------------------------------*/
1001
1002/* Compare error contexts, to detect duplicates. Note that if they
1003 are otherwise the same, the faulting addrs and associated rwoffsets
1004 are allowed to be different. */
1005Bool MC_(eq_Error) ( VgRes res, Error* e1, Error* e2 )
1006{
1007 MC_Error* extra1 = VG_(get_error_extra)(e1);
1008 MC_Error* extra2 = VG_(get_error_extra)(e2);
1009
1010 /* Guaranteed by calling function */
1011 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
1012
1013 switch (VG_(get_error_kind)(e1)) {
1014 case Err_CoreMem: {
1015 Char *e1s, *e2s;
1016 e1s = VG_(get_error_string)(e1);
1017 e2s = VG_(get_error_string)(e2);
1018 if (e1s == e2s) return True;
1019 if (VG_STREQ(e1s, e2s)) return True;
1020 return False;
1021 }
1022
1023 case Err_RegParam:
1024 return VG_STREQ(VG_(get_error_string)(e1), VG_(get_error_string)(e2));
1025
1026 // Perhaps we should also check the addrinfo.akinds for equality.
1027 // That would result in more error reports, but only in cases where
1028 // a register contains uninitialised bytes and points to memory
1029 // containing uninitialised bytes. Currently, the 2nd of those to be
1030 // detected won't be reported. That is (nearly?) always the memory
1031 // error, which is good.
1032 case Err_MemParam:
1033 if (!VG_STREQ(VG_(get_error_string)(e1),
1034 VG_(get_error_string)(e2))) return False;
1035 // fall through
1036 case Err_User:
1037 return ( extra1->Err.User.isAddrErr == extra2->Err.User.isAddrErr
1038 ? True : False );
1039
1040 case Err_Free:
1041 case Err_FreeMismatch:
1042 case Err_Jump:
1043 case Err_IllegalMempool:
1044 case Err_Overlap:
1045 case Err_Cond:
1046 return True;
1047
1048 case Err_Addr:
1049 return ( extra1->Err.Addr.szB == extra2->Err.Addr.szB
1050 ? True : False );
1051
1052 case Err_Value:
1053 return ( extra1->Err.Value.szB == extra2->Err.Value.szB
1054 ? True : False );
1055
1056 case Err_Leak:
1057 VG_(tool_panic)("Shouldn't get Err_Leak in mc_eq_Error,\n"
1058 "since it's handled with VG_(unique_error)()!");
1059
1060 default:
1061 VG_(printf)("Error:\n unknown error code %d\n",
1062 VG_(get_error_kind)(e1));
1063 VG_(tool_panic)("unknown error code in mc_eq_Error");
1064 }
1065}
1066
sewardj62b91042011-01-23 20:45:53 +00001067/* Functions used when searching MC_Chunk lists */
1068static
1069Bool addr_is_in_MC_Chunk_default_REDZONE_SZB(MC_Chunk* mc, Addr a)
sewardj7ce71662008-05-02 10:33:15 +00001070{
sewardj7ce71662008-05-02 10:33:15 +00001071 return VG_(addr_is_in_block)( a, mc->data, mc->szB,
1072 MC_MALLOC_REDZONE_SZB );
1073}
sewardj62b91042011-01-23 20:45:53 +00001074static
1075Bool addr_is_in_MC_Chunk_with_REDZONE_SZB(MC_Chunk* mc, Addr a, SizeT rzB)
1076{
1077 return VG_(addr_is_in_block)( a, mc->data, mc->szB,
1078 rzB );
1079}
sewardj7ce71662008-05-02 10:33:15 +00001080
sewardj62b91042011-01-23 20:45:53 +00001081// Forward declarations
sewardj7ce71662008-05-02 10:33:15 +00001082static Bool client_block_maybe_describe( Addr a, AddrInfo* ai );
sewardj62b91042011-01-23 20:45:53 +00001083static Bool mempool_block_maybe_describe( Addr a, AddrInfo* ai );
sewardj7ce71662008-05-02 10:33:15 +00001084
1085
1086/* Describe an address as best you can, for error messages,
1087 putting the result in ai. */
1088static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
1089{
1090 MC_Chunk* mc;
1091 ThreadId tid;
1092 Addr stack_min, stack_max;
1093 VgSectKind sect;
1094
1095 tl_assert(Addr_Undescribed == ai->tag);
1096
sewardj62b91042011-01-23 20:45:53 +00001097 /* -- Perhaps it's a user-named block? -- */
sewardj7ce71662008-05-02 10:33:15 +00001098 if (client_block_maybe_describe( a, ai )) {
1099 return;
1100 }
sewardj62b91042011-01-23 20:45:53 +00001101 /* -- Perhaps it's in mempool block? -- */
1102 if (mempool_block_maybe_describe( a, ai )) {
1103 return;
1104 }
sewardj6b523cd2009-07-15 14:49:40 +00001105 /* -- Search for a recently freed block which might bracket it. -- */
sewardj7ce71662008-05-02 10:33:15 +00001106 mc = MC_(get_freed_list_head)();
1107 while (mc) {
sewardj62b91042011-01-23 20:45:53 +00001108 if (addr_is_in_MC_Chunk_default_REDZONE_SZB(mc, a)) {
sewardj7ce71662008-05-02 10:33:15 +00001109 ai->tag = Addr_Block;
1110 ai->Addr.Block.block_kind = Block_Freed;
1111 ai->Addr.Block.block_desc = "block";
1112 ai->Addr.Block.block_szB = mc->szB;
sewardj56adc352008-05-02 11:25:17 +00001113 ai->Addr.Block.rwoffset = (Word)a - (Word)mc->data;
sewardj7ce71662008-05-02 10:33:15 +00001114 ai->Addr.Block.lastchange = mc->where;
1115 return;
1116 }
1117 mc = mc->next;
1118 }
sewardj6b523cd2009-07-15 14:49:40 +00001119 /* -- Search for a currently malloc'd block which might bracket it. -- */
sewardj7ce71662008-05-02 10:33:15 +00001120 VG_(HT_ResetIter)(MC_(malloc_list));
1121 while ( (mc = VG_(HT_Next)(MC_(malloc_list))) ) {
sewardj62b91042011-01-23 20:45:53 +00001122 if (addr_is_in_MC_Chunk_default_REDZONE_SZB(mc, a)) {
sewardj7ce71662008-05-02 10:33:15 +00001123 ai->tag = Addr_Block;
1124 ai->Addr.Block.block_kind = Block_Mallocd;
1125 ai->Addr.Block.block_desc = "block";
1126 ai->Addr.Block.block_szB = mc->szB;
sewardj56adc352008-05-02 11:25:17 +00001127 ai->Addr.Block.rwoffset = (Word)a - (Word)mc->data;
sewardj7ce71662008-05-02 10:33:15 +00001128 ai->Addr.Block.lastchange = mc->where;
1129 return;
1130 }
1131 }
sewardj6b523cd2009-07-15 14:49:40 +00001132 /* -- Perhaps the variable type/location data describes it? -- */
1133 ai->Addr.Variable.descr1
1134 = VG_(newXA)( VG_(malloc), "mc.da.descr1",
1135 VG_(free), sizeof(HChar) );
1136 ai->Addr.Variable.descr2
1137 = VG_(newXA)( VG_(malloc), "mc.da.descr2",
1138 VG_(free), sizeof(HChar) );
1139
1140 (void) VG_(get_data_description)( ai->Addr.Variable.descr1,
1141 ai->Addr.Variable.descr2, a );
1142 /* If there's nothing in descr1/2, free them. Why is it safe to to
1143 VG_(indexXA) at zero here? Because VG_(get_data_description)
1144 guarantees to zero terminate descr1/2 regardless of the outcome
1145 of the call. So there's always at least one element in each XA
1146 after the call.
1147 */
1148 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr1, 0 ))) {
1149 VG_(deleteXA)( ai->Addr.Variable.descr1 );
1150 ai->Addr.Variable.descr1 = NULL;
1151 }
1152 if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
1153 VG_(deleteXA)( ai->Addr.Variable.descr2 );
1154 ai->Addr.Variable.descr2 = NULL;
1155 }
1156 /* Assume (assert) that VG_(get_data_description) fills in descr1
1157 before it fills in descr2 */
1158 if (ai->Addr.Variable.descr1 == NULL)
1159 tl_assert(ai->Addr.Variable.descr2 == NULL);
1160 /* So did we get lucky? */
1161 if (ai->Addr.Variable.descr1 != NULL) {
sewardj7ce71662008-05-02 10:33:15 +00001162 ai->tag = Addr_Variable;
sewardj7ce71662008-05-02 10:33:15 +00001163 return;
1164 }
sewardj6b523cd2009-07-15 14:49:40 +00001165 /* -- Have a look at the low level data symbols - perhaps it's in
1166 there. -- */
sewardj7ce71662008-05-02 10:33:15 +00001167 VG_(memset)( &ai->Addr.DataSym.name,
1168 0, sizeof(ai->Addr.DataSym.name));
1169 if (VG_(get_datasym_and_offset)(
1170 a, &ai->Addr.DataSym.name[0],
1171 sizeof(ai->Addr.DataSym.name)-1,
1172 &ai->Addr.DataSym.offset )) {
1173 ai->tag = Addr_DataSym;
1174 tl_assert( ai->Addr.DataSym.name
1175 [ sizeof(ai->Addr.DataSym.name)-1 ] == 0);
1176 return;
1177 }
sewardj6b523cd2009-07-15 14:49:40 +00001178 /* -- Perhaps it's on a thread's stack? -- */
sewardj7ce71662008-05-02 10:33:15 +00001179 VG_(thread_stack_reset_iter)(&tid);
1180 while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
1181 if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
1182 ai->tag = Addr_Stack;
1183 ai->Addr.Stack.tid = tid;
1184 return;
1185 }
1186 }
sewardj6b523cd2009-07-15 14:49:40 +00001187 /* -- last ditch attempt at classification -- */
sewardj7ce71662008-05-02 10:33:15 +00001188 tl_assert( sizeof(ai->Addr.SectKind.objname) > 4 );
1189 VG_(memset)( &ai->Addr.SectKind.objname,
1190 0, sizeof(ai->Addr.SectKind.objname));
1191 VG_(strcpy)( ai->Addr.SectKind.objname, "???" );
sewardje3f1e592009-07-31 09:41:29 +00001192 sect = VG_(DebugInfo_sect_kind)( &ai->Addr.SectKind.objname[0],
1193 sizeof(ai->Addr.SectKind.objname)-1, a);
sewardj7ce71662008-05-02 10:33:15 +00001194 if (sect != Vg_SectUnknown) {
1195 ai->tag = Addr_SectKind;
1196 ai->Addr.SectKind.kind = sect;
1197 tl_assert( ai->Addr.SectKind.objname
1198 [ sizeof(ai->Addr.SectKind.objname)-1 ] == 0);
1199 return;
1200 }
sewardj6b523cd2009-07-15 14:49:40 +00001201 /* -- Clueless ... -- */
sewardj7ce71662008-05-02 10:33:15 +00001202 ai->tag = Addr_Unknown;
1203 return;
1204}
1205
sewardj3b290482011-05-06 21:02:55 +00001206void MC_(pp_describe_addr) ( Addr a )
1207{
1208 AddrInfo ai;
1209
1210 ai.tag = Addr_Undescribed;
1211 describe_addr (a, &ai);
1212 mc_pp_AddrInfo (a, &ai, /* maybe_gcc */ False);
1213}
1214
sewardj7ce71662008-05-02 10:33:15 +00001215/* Fill in *origin_ec as specified by otag, or NULL it out if otag
1216 does not refer to a known origin. */
1217static void update_origin ( /*OUT*/ExeContext** origin_ec,
1218 UInt otag )
1219{
1220 UInt ecu = otag & ~3;
1221 *origin_ec = NULL;
1222 if (VG_(is_plausible_ECU)(ecu)) {
1223 *origin_ec = VG_(get_ExeContext_from_ECU)( ecu );
1224 }
1225}
1226
1227/* Updates the copy with address info if necessary (but not for all errors). */
1228UInt MC_(update_Error_extra)( Error* err )
1229{
1230 MC_Error* extra = VG_(get_error_extra)(err);
1231
1232 switch (VG_(get_error_kind)(err)) {
1233 // These ones don't have addresses associated with them, and so don't
1234 // need any updating.
1235 case Err_CoreMem:
1236 //case Err_Value:
1237 //case Err_Cond:
1238 case Err_Overlap:
1239 // For Err_Leaks the returned size does not matter -- they are always
1240 // shown with VG_(unique_error)() so they 'extra' not copied. But
1241 // we make it consistent with the others.
1242 case Err_Leak:
1243 return sizeof(MC_Error);
1244
1245 // For value errors, get the ExeContext corresponding to the
1246 // origin tag. Note that it is a kludge to assume that
1247 // a length-1 trace indicates a stack origin. FIXME.
1248 case Err_Value:
1249 update_origin( &extra->Err.Value.origin_ec,
1250 extra->Err.Value.otag );
1251 return sizeof(MC_Error);
1252 case Err_Cond:
1253 update_origin( &extra->Err.Cond.origin_ec,
1254 extra->Err.Cond.otag );
1255 return sizeof(MC_Error);
1256 case Err_RegParam:
1257 update_origin( &extra->Err.RegParam.origin_ec,
1258 extra->Err.RegParam.otag );
1259 return sizeof(MC_Error);
1260
1261 // These ones always involve a memory address.
1262 case Err_Addr:
1263 describe_addr ( VG_(get_error_address)(err),
1264 &extra->Err.Addr.ai );
1265 return sizeof(MC_Error);
1266 case Err_MemParam:
1267 describe_addr ( VG_(get_error_address)(err),
1268 &extra->Err.MemParam.ai );
1269 update_origin( &extra->Err.MemParam.origin_ec,
1270 extra->Err.MemParam.otag );
1271 return sizeof(MC_Error);
1272 case Err_Jump:
1273 describe_addr ( VG_(get_error_address)(err),
1274 &extra->Err.Jump.ai );
1275 return sizeof(MC_Error);
1276 case Err_User:
1277 describe_addr ( VG_(get_error_address)(err),
1278 &extra->Err.User.ai );
1279 update_origin( &extra->Err.User.origin_ec,
1280 extra->Err.User.otag );
1281 return sizeof(MC_Error);
1282 case Err_Free:
1283 describe_addr ( VG_(get_error_address)(err),
1284 &extra->Err.Free.ai );
1285 return sizeof(MC_Error);
1286 case Err_IllegalMempool:
1287 describe_addr ( VG_(get_error_address)(err),
1288 &extra->Err.IllegalMempool.ai );
1289 return sizeof(MC_Error);
1290
1291 // Err_FreeMismatches have already had their address described; this is
1292 // possible because we have the MC_Chunk on hand when the error is
1293 // detected. However, the address may be part of a user block, and if so
1294 // we override the pre-determined description with a user block one.
1295 case Err_FreeMismatch: {
1296 tl_assert(extra && Block_Mallocd ==
1297 extra->Err.FreeMismatch.ai.Addr.Block.block_kind);
1298 (void)client_block_maybe_describe( VG_(get_error_address)(err),
1299 &extra->Err.FreeMismatch.ai );
1300 return sizeof(MC_Error);
1301 }
1302
1303 default: VG_(tool_panic)("mc_update_extra: bad errkind");
1304 }
1305}
1306
sewardj62b91042011-01-23 20:45:53 +00001307
sewardj7ce71662008-05-02 10:33:15 +00001308static Bool client_block_maybe_describe( Addr a,
1309 /*OUT*/AddrInfo* ai )
1310{
sewardj56adc352008-05-02 11:25:17 +00001311 UWord i;
sewardj7ce71662008-05-02 10:33:15 +00001312 CGenBlock* cgbs = NULL;
1313 UWord cgb_used = 0;
sewardj56adc352008-05-02 11:25:17 +00001314
sewardj7ce71662008-05-02 10:33:15 +00001315 MC_(get_ClientBlock_array)( &cgbs, &cgb_used );
1316 if (cgbs == NULL)
1317 tl_assert(cgb_used == 0);
1318
1319 /* Perhaps it's a general block ? */
1320 for (i = 0; i < cgb_used; i++) {
1321 if (cgbs[i].start == 0 && cgbs[i].size == 0)
1322 continue;
1323 // Use zero as the redzone for client blocks.
1324 if (VG_(addr_is_in_block)(a, cgbs[i].start, cgbs[i].size, 0)) {
sewardj7ce71662008-05-02 10:33:15 +00001325 ai->tag = Addr_Block;
1326 ai->Addr.Block.block_kind = Block_UserG;
1327 ai->Addr.Block.block_desc = cgbs[i].desc;
1328 ai->Addr.Block.block_szB = cgbs[i].size;
sewardj56adc352008-05-02 11:25:17 +00001329 ai->Addr.Block.rwoffset = (Word)(a) - (Word)(cgbs[i].start);
sewardj7ce71662008-05-02 10:33:15 +00001330 ai->Addr.Block.lastchange = cgbs[i].where;
1331 return True;
1332 }
1333 }
1334 return False;
1335}
1336
1337
sewardj62b91042011-01-23 20:45:53 +00001338static Bool mempool_block_maybe_describe( Addr a,
1339 /*OUT*/AddrInfo* ai )
1340{
1341 MC_Mempool* mp;
1342 tl_assert( MC_(mempool_list) );
1343
1344 VG_(HT_ResetIter)( MC_(mempool_list) );
1345 while ( (mp = VG_(HT_Next)(MC_(mempool_list))) ) {
1346 if (mp->chunks != NULL) {
1347 MC_Chunk* mc;
1348 VG_(HT_ResetIter)(mp->chunks);
1349 while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
1350 if (addr_is_in_MC_Chunk_with_REDZONE_SZB(mc, a, mp->rzB)) {
1351 ai->tag = Addr_Block;
1352 ai->Addr.Block.block_kind = Block_MempoolChunk;
1353 ai->Addr.Block.block_desc = "block";
1354 ai->Addr.Block.block_szB = mc->szB;
1355 ai->Addr.Block.rwoffset = (Word)a - (Word)mc->data;
1356 ai->Addr.Block.lastchange = mc->where;
1357 return True;
1358 }
1359 }
1360 }
1361 }
1362 return False;
1363}
1364
1365
sewardj7ce71662008-05-02 10:33:15 +00001366/*------------------------------------------------------------*/
1367/*--- Suppressions ---*/
1368/*------------------------------------------------------------*/
1369
1370typedef
1371 enum {
1372 ParamSupp, // Bad syscall params
1373 UserSupp, // Errors arising from client-request checks
1374 CoreMemSupp, // Memory errors in core (pthread ops, signal handling)
1375
1376 // Undefined value errors of given size
1377 Value1Supp, Value2Supp, Value4Supp, Value8Supp, Value16Supp,
1378
1379 // Undefined value error in conditional.
1380 CondSupp,
1381
1382 // Unaddressable read/write attempt at given size
1383 Addr1Supp, Addr2Supp, Addr4Supp, Addr8Supp, Addr16Supp,
1384
1385 JumpSupp, // Jump to unaddressable target
1386 FreeSupp, // Invalid or mismatching free
1387 OverlapSupp, // Overlapping blocks in memcpy(), strcpy(), etc
1388 LeakSupp, // Something to be suppressed in a leak check.
1389 MempoolSupp, // Memory pool suppression.
1390 }
1391 MC_SuppKind;
1392
1393Bool MC_(is_recognised_suppression) ( Char* name, Supp* su )
1394{
1395 SuppKind skind;
1396
1397 if (VG_STREQ(name, "Param")) skind = ParamSupp;
1398 else if (VG_STREQ(name, "User")) skind = UserSupp;
1399 else if (VG_STREQ(name, "CoreMem")) skind = CoreMemSupp;
1400 else if (VG_STREQ(name, "Addr1")) skind = Addr1Supp;
1401 else if (VG_STREQ(name, "Addr2")) skind = Addr2Supp;
1402 else if (VG_STREQ(name, "Addr4")) skind = Addr4Supp;
1403 else if (VG_STREQ(name, "Addr8")) skind = Addr8Supp;
1404 else if (VG_STREQ(name, "Addr16")) skind = Addr16Supp;
1405 else if (VG_STREQ(name, "Jump")) skind = JumpSupp;
1406 else if (VG_STREQ(name, "Free")) skind = FreeSupp;
1407 else if (VG_STREQ(name, "Leak")) skind = LeakSupp;
1408 else if (VG_STREQ(name, "Overlap")) skind = OverlapSupp;
1409 else if (VG_STREQ(name, "Mempool")) skind = MempoolSupp;
1410 else if (VG_STREQ(name, "Cond")) skind = CondSupp;
1411 else if (VG_STREQ(name, "Value0")) skind = CondSupp; /* backwards compat */
1412 else if (VG_STREQ(name, "Value1")) skind = Value1Supp;
1413 else if (VG_STREQ(name, "Value2")) skind = Value2Supp;
1414 else if (VG_STREQ(name, "Value4")) skind = Value4Supp;
1415 else if (VG_STREQ(name, "Value8")) skind = Value8Supp;
1416 else if (VG_STREQ(name, "Value16")) skind = Value16Supp;
1417 else
1418 return False;
1419
1420 VG_(set_supp_kind)(su, skind);
1421 return True;
1422}
1423
njn35db56c2009-07-24 07:38:29 +00001424Bool MC_(read_extra_suppression_info) ( Int fd, Char** bufpp,
1425 SizeT* nBufp, Supp *su )
sewardj7ce71662008-05-02 10:33:15 +00001426{
1427 Bool eof;
1428
1429 if (VG_(get_supp_kind)(su) == ParamSupp) {
bart050eec52009-07-27 12:03:03 +00001430 eof = VG_(get_line) ( fd, bufpp, nBufp, NULL );
sewardj7ce71662008-05-02 10:33:15 +00001431 if (eof) return False;
njn35db56c2009-07-24 07:38:29 +00001432 VG_(set_supp_string)(su, VG_(strdup)("mc.resi.1", *bufpp));
sewardj7ce71662008-05-02 10:33:15 +00001433 }
1434 return True;
1435}
1436
1437Bool MC_(error_matches_suppression) ( Error* err, Supp* su )
1438{
1439 Int su_szB;
1440 MC_Error* extra = VG_(get_error_extra)(err);
1441 ErrorKind ekind = VG_(get_error_kind )(err);
1442
1443 switch (VG_(get_supp_kind)(su)) {
1444 case ParamSupp:
1445 return ((ekind == Err_RegParam || ekind == Err_MemParam)
1446 && VG_STREQ(VG_(get_error_string)(err),
1447 VG_(get_supp_string)(su)));
1448
1449 case UserSupp:
1450 return (ekind == Err_User);
1451
1452 case CoreMemSupp:
1453 return (ekind == Err_CoreMem
1454 && VG_STREQ(VG_(get_error_string)(err),
1455 VG_(get_supp_string)(su)));
1456
1457 case Value1Supp: su_szB = 1; goto value_case;
1458 case Value2Supp: su_szB = 2; goto value_case;
1459 case Value4Supp: su_szB = 4; goto value_case;
1460 case Value8Supp: su_szB = 8; goto value_case;
1461 case Value16Supp:su_szB =16; goto value_case;
1462 value_case:
1463 return (ekind == Err_Value && extra->Err.Value.szB == su_szB);
1464
1465 case CondSupp:
1466 return (ekind == Err_Cond);
1467
1468 case Addr1Supp: su_szB = 1; goto addr_case;
1469 case Addr2Supp: su_szB = 2; goto addr_case;
1470 case Addr4Supp: su_szB = 4; goto addr_case;
1471 case Addr8Supp: su_szB = 8; goto addr_case;
1472 case Addr16Supp:su_szB =16; goto addr_case;
1473 addr_case:
1474 return (ekind == Err_Addr && extra->Err.Addr.szB == su_szB);
1475
1476 case JumpSupp:
1477 return (ekind == Err_Jump);
1478
1479 case FreeSupp:
1480 return (ekind == Err_Free || ekind == Err_FreeMismatch);
1481
1482 case OverlapSupp:
1483 return (ekind == Err_Overlap);
1484
1485 case LeakSupp:
1486 return (ekind == Err_Leak);
1487
1488 case MempoolSupp:
1489 return (ekind == Err_IllegalMempool);
1490
1491 default:
1492 VG_(printf)("Error:\n"
1493 " unknown suppression type %d\n",
1494 VG_(get_supp_kind)(su));
1495 VG_(tool_panic)("unknown suppression type in "
1496 "MC_(error_matches_suppression)");
1497 }
1498}
1499
1500Char* MC_(get_error_name) ( Error* err )
1501{
1502 switch (VG_(get_error_kind)(err)) {
1503 case Err_RegParam: return "Param";
1504 case Err_MemParam: return "Param";
1505 case Err_User: return "User";
1506 case Err_FreeMismatch: return "Free";
1507 case Err_IllegalMempool: return "Mempool";
1508 case Err_Free: return "Free";
1509 case Err_Jump: return "Jump";
1510 case Err_CoreMem: return "CoreMem";
1511 case Err_Overlap: return "Overlap";
1512 case Err_Leak: return "Leak";
1513 case Err_Cond: return "Cond";
1514 case Err_Addr: {
1515 MC_Error* extra = VG_(get_error_extra)(err);
1516 switch ( extra->Err.Addr.szB ) {
1517 case 1: return "Addr1";
1518 case 2: return "Addr2";
1519 case 4: return "Addr4";
1520 case 8: return "Addr8";
1521 case 16: return "Addr16";
1522 default: VG_(tool_panic)("unexpected size for Addr");
1523 }
1524 }
1525 case Err_Value: {
1526 MC_Error* extra = VG_(get_error_extra)(err);
1527 switch ( extra->Err.Value.szB ) {
1528 case 1: return "Value1";
1529 case 2: return "Value2";
1530 case 4: return "Value4";
1531 case 8: return "Value8";
1532 case 16: return "Value16";
1533 default: VG_(tool_panic)("unexpected size for Value");
1534 }
1535 }
1536 default: VG_(tool_panic)("get_error_name: unexpected type");
1537 }
1538}
1539
sewardj588adef2009-08-15 22:41:51 +00001540Bool MC_(get_extra_suppression_info) ( Error* err,
1541 /*OUT*/Char* buf, Int nBuf )
sewardj7ce71662008-05-02 10:33:15 +00001542{
1543 ErrorKind ekind = VG_(get_error_kind )(err);
sewardj588adef2009-08-15 22:41:51 +00001544 tl_assert(buf);
1545 tl_assert(nBuf >= 16); // stay sane
sewardj7ce71662008-05-02 10:33:15 +00001546 if (Err_RegParam == ekind || Err_MemParam == ekind) {
sewardj588adef2009-08-15 22:41:51 +00001547 Char* errstr = VG_(get_error_string)(err);
1548 tl_assert(errstr);
1549 VG_(snprintf)(buf, nBuf-1, "%s", errstr);
1550 return True;
1551 } else {
1552 return False;
sewardj7ce71662008-05-02 10:33:15 +00001553 }
1554}
1555
1556
1557/*--------------------------------------------------------------------*/
1558/*--- end mc_errors.c ---*/
1559/*--------------------------------------------------------------------*/