mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-09 08:56:15 +00:00
812 lines
26 KiB
C
812 lines
26 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- Ptrcheck: a pointer-use checker. ---*/
|
|
/*--- Provides stuff shared between sg_ and h_ subtools. ---*/
|
|
/*--- pc_common.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
|
use in programs.
|
|
|
|
Copyright (C) 2008-2015 OpenWorks Ltd
|
|
info@open-works.co.uk
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
|
|
Neither the names of the U.S. Department of Energy nor the
|
|
University of California nor the names of its contributors may be
|
|
used to endorse or promote products derived from this software
|
|
without prior written permission.
|
|
*/
|
|
|
|
#include "pub_tool_basics.h"
|
|
#include "pub_tool_libcbase.h"
|
|
#include "pub_tool_libcprint.h"
|
|
#include "pub_tool_xarray.h"
|
|
#include "pub_tool_mallocfree.h"
|
|
#include "pub_tool_libcassert.h"
|
|
#include "pub_tool_options.h"
|
|
#include "pub_tool_replacemalloc.h"
|
|
#include "pub_tool_execontext.h"
|
|
#include "pub_tool_tooliface.h" // CorePart
|
|
#include "pub_tool_threadstate.h" // VG_(get_running_tid)
|
|
#include "pub_tool_debuginfo.h"
|
|
|
|
#include "pc_common.h" // self, & Seg
|
|
|
|
#include "h_main.h" // NONPTR, BOTTOM, UNKNOWN
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// Command line options //
|
|
// //
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
Bool h_clo_partial_loads_ok = True; /* user visible */
|
|
/* Bool h_clo_lossage_check = False; */ /* dev flag only */
|
|
Bool sg_clo_enable_sg_checks = True; /* user visible */
|
|
|
|
Bool pc_process_cmd_line_options(const HChar* arg)
|
|
{
|
|
if VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok) {}
|
|
/* else if VG_BOOL_CLO(arg, "--lossage-check", h_clo_lossage_check) {} */
|
|
else if VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks) {}
|
|
else
|
|
return VG_(replacement_malloc_process_cmd_line_option)(arg);
|
|
|
|
return True;
|
|
}
|
|
|
|
void pc_print_usage(void)
|
|
{
|
|
VG_(printf)(
|
|
" --partial-loads-ok=no|yes same as for Memcheck [yes]\n"
|
|
" --enable-sg-checks=no|yes enable stack & global array checking? [yes]\n"
|
|
);
|
|
}
|
|
|
|
void pc_print_debug_usage(void)
|
|
{
|
|
VG_(printf)(
|
|
" (none)\n"
|
|
//" --lossage-check=no|yes gather stats for quality control [no]\n"
|
|
);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// Error management -- storage //
|
|
// //
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
/* What kind of error it is. */
|
|
typedef
|
|
enum {
|
|
XE_SorG=1202, // sg: stack or global array inconsistency
|
|
XE_Heap, // h: mismatched ptr/addr segments on load/store
|
|
XE_Arith, // h: bad arithmetic between two segment pointers
|
|
XE_SysParam // h: block straddling >1 segment passed to syscall
|
|
}
|
|
XErrorTag;
|
|
|
|
typedef
|
|
enum {
|
|
XS_SorG=2021,
|
|
XS_Heap,
|
|
XS_Arith,
|
|
XS_SysParam
|
|
}
|
|
XSuppTag;
|
|
|
|
typedef
|
|
struct {
|
|
XErrorTag tag;
|
|
union {
|
|
struct {
|
|
Addr addr;
|
|
SSizeT sszB; /* -ve is write, +ve is read */
|
|
HChar expect[128];
|
|
HChar actual[128];
|
|
HChar delta[32]; // text showing relation to expected
|
|
} SorG;
|
|
struct {
|
|
Addr addr;
|
|
SSizeT sszB; /* -ve is write, +ve is read */
|
|
Seg* vseg;
|
|
XArray* descr1; /* XArray* of HChar */
|
|
XArray* descr2; /* XArray* of HChar */
|
|
const HChar* datasym;
|
|
PtrdiffT datasymoff;
|
|
} Heap;
|
|
struct {
|
|
Seg* seg1;
|
|
Seg* seg2;
|
|
const HChar* opname; // user-understandable text name
|
|
} Arith;
|
|
struct {
|
|
CorePart part;
|
|
Addr lo;
|
|
Addr hi;
|
|
Seg* seglo;
|
|
Seg* seghi;
|
|
} SysParam;
|
|
} XE;
|
|
}
|
|
XError;
|
|
|
|
|
|
void sg_record_error_SorG ( ThreadId tid,
|
|
Addr addr, SSizeT sszB,
|
|
HChar* expect, HChar* actual, HChar* delta )
|
|
{
|
|
XError xe;
|
|
VG_(memset)(&xe, 0, sizeof(xe));
|
|
xe.tag = XE_SorG;
|
|
xe.XE.SorG.addr = addr;
|
|
xe.XE.SorG.sszB = sszB;
|
|
VG_(strncpy)( &xe.XE.SorG.expect[0],
|
|
expect, sizeof(xe.XE.SorG.expect) );
|
|
VG_(strncpy)( &xe.XE.SorG.actual[0],
|
|
actual, sizeof(xe.XE.SorG.actual) );
|
|
VG_(strncpy)( &xe.XE.SorG.delta[0],
|
|
delta, sizeof(xe.XE.SorG.delta) );
|
|
xe.XE.SorG.expect[ sizeof(xe.XE.SorG.expect)-1 ] = 0;
|
|
xe.XE.SorG.actual[ sizeof(xe.XE.SorG.actual)-1 ] = 0;
|
|
xe.XE.SorG.delta[ sizeof(xe.XE.SorG.delta)-1 ] = 0;
|
|
VG_(maybe_record_error)( tid, XE_SorG, 0, NULL, &xe );
|
|
}
|
|
|
|
void h_record_heap_error( Addr a, SizeT size, Seg* vseg, Bool is_write )
|
|
{
|
|
XError xe;
|
|
tl_assert(size > 0);
|
|
VG_(memset)(&xe, 0, sizeof(xe));
|
|
xe.tag = XE_Heap;
|
|
xe.XE.Heap.addr = a;
|
|
xe.XE.Heap.sszB = is_write ? -size : size;
|
|
xe.XE.Heap.vseg = vseg;
|
|
VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Heap,
|
|
/*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
|
|
}
|
|
|
|
void h_record_arith_error( Seg* seg1, Seg* seg2, HChar* opname )
|
|
{
|
|
XError xe;
|
|
VG_(memset)(&xe, 0, sizeof(xe));
|
|
xe.tag = XE_Arith;
|
|
xe.XE.Arith.seg1 = seg1;
|
|
xe.XE.Arith.seg2 = seg2;
|
|
xe.XE.Arith.opname = opname;
|
|
VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Arith,
|
|
/*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
|
|
}
|
|
|
|
void h_record_sysparam_error( ThreadId tid, CorePart part, const HChar* s,
|
|
Addr lo, Addr hi, Seg* seglo, Seg* seghi )
|
|
{
|
|
XError xe;
|
|
VG_(memset)(&xe, 0, sizeof(xe));
|
|
xe.tag = XE_SysParam;
|
|
xe.XE.SysParam.part = part;
|
|
xe.XE.SysParam.lo = lo;
|
|
xe.XE.SysParam.hi = hi;
|
|
xe.XE.SysParam.seglo = seglo;
|
|
xe.XE.SysParam.seghi = seghi;
|
|
VG_(maybe_record_error)( tid, XE_SysParam, /*a*/(Addr)0, /*str*/s,
|
|
/*extra*/(void*)&xe);
|
|
}
|
|
|
|
|
|
Bool pc_eq_Error ( VgRes res, const Error* e1, const Error* e2 )
|
|
{
|
|
XError *xe1, *xe2;
|
|
tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
|
|
//tl_assert(VG_(get_error_string)(e1) == NULL);
|
|
//tl_assert(VG_(get_error_string)(e2) == NULL);
|
|
|
|
xe1 = (XError*)VG_(get_error_extra)(e1);
|
|
xe2 = (XError*)VG_(get_error_extra)(e2);
|
|
tl_assert(xe1);
|
|
tl_assert(xe2);
|
|
|
|
if (xe1->tag != xe2->tag)
|
|
return False;
|
|
|
|
switch (xe1->tag) {
|
|
case XE_SorG:
|
|
return //xe1->XE.SorG.addr == xe2->XE.SorG.addr
|
|
//&&
|
|
xe1->XE.SorG.sszB == xe2->XE.SorG.sszB
|
|
&& 0 == VG_(strncmp)( &xe1->XE.SorG.expect[0],
|
|
&xe2->XE.SorG.expect[0],
|
|
sizeof(xe1->XE.SorG.expect) )
|
|
&& 0 == VG_(strncmp)( &xe1->XE.SorG.actual[0],
|
|
&xe2->XE.SorG.actual[0],
|
|
sizeof(xe1->XE.SorG.actual) );
|
|
case XE_Heap:
|
|
case XE_Arith:
|
|
case XE_SysParam:
|
|
return True;
|
|
default:
|
|
VG_(tool_panic)("eq_Error: unrecognised error kind");
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// Error management -- printing //
|
|
// //
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
/* This is the "this error is due to be printed shortly; so have a
|
|
look at it any print any preamble you want" function. Which, in
|
|
Ptrcheck, we don't use. Hence a no-op.
|
|
*/
|
|
void pc_before_pp_Error ( const Error* err ) {
|
|
}
|
|
|
|
/* Do a printf-style operation on either the XML or normal output
|
|
channel, depending on the setting of VG_(clo_xml).
|
|
*/
|
|
static void emit_WRK ( const HChar* format, va_list vargs )
|
|
{
|
|
if (VG_(clo_xml)) {
|
|
VG_(vprintf_xml)(format, vargs);
|
|
} else {
|
|
VG_(vmessage)(Vg_UserMsg, format, vargs);
|
|
}
|
|
}
|
|
static void emit ( const HChar* format, ... ) PRINTF_CHECK(1, 2);
|
|
static void emit ( const HChar* format, ... )
|
|
{
|
|
va_list vargs;
|
|
va_start(vargs, format);
|
|
emit_WRK(format, vargs);
|
|
va_end(vargs);
|
|
}
|
|
static void emiN ( const HChar* format, ... ) /* With NO FORMAT CHECK */
|
|
{
|
|
va_list vargs;
|
|
va_start(vargs, format);
|
|
emit_WRK(format, vargs);
|
|
va_end(vargs);
|
|
}
|
|
|
|
|
|
static const HChar* readwrite(SSizeT sszB)
|
|
{
|
|
return ( sszB < 0 ? "write" : "read" );
|
|
}
|
|
|
|
static Word Word__abs ( Word w ) {
|
|
return w < 0 ? -w : w;
|
|
}
|
|
|
|
void pc_pp_Error ( const Error* err )
|
|
{
|
|
const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
|
|
|
|
XError *xe = (XError*)VG_(get_error_extra)(err);
|
|
tl_assert(xe);
|
|
|
|
if (xml)
|
|
emit( " <kind>%s</kind>\n", pc_get_error_name(err));
|
|
|
|
switch (VG_(get_error_kind)(err)) {
|
|
|
|
//----------------------------------------------------------
|
|
case XE_SorG:
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>Invalid %s of size %ld</what>\n",
|
|
xe->XE.SorG.sszB < 0 ? "write" : "read",
|
|
Word__abs(xe->XE.SorG.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " <auxwhat>Address %#lx expected vs actual:</auxwhat>\n",
|
|
xe->XE.SorG.addr );
|
|
emiN( " <auxwhat>Expected: %pS</auxwhat>\n",
|
|
&xe->XE.SorG.expect[0] );
|
|
emiN( " <auxwhat>Actual: %pS</auxwhat>\n",
|
|
&xe->XE.SorG.actual[0] );
|
|
|
|
} else {
|
|
|
|
emit( "Invalid %s of size %ld\n",
|
|
xe->XE.SorG.sszB < 0 ? "write" : "read",
|
|
Word__abs(xe->XE.SorG.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
|
|
emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
|
|
emit( " Actual: %s\n", &xe->XE.SorG.actual[0] );
|
|
if (xe->XE.SorG.delta[0] != 0)
|
|
emit(" Actual: is %s Expected\n", &xe->XE.SorG.delta[0]);
|
|
}
|
|
break;
|
|
|
|
//----------------------------------------------------------
|
|
case XE_Heap: {
|
|
const HChar *place, *legit, *how_invalid;
|
|
Addr a = xe->XE.Heap.addr;
|
|
Seg* vseg = xe->XE.Heap.vseg;
|
|
|
|
tl_assert(is_known_segment(vseg) || NONPTR == vseg);
|
|
|
|
if (NONPTR == vseg) {
|
|
// Access via a non-pointer
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>Invalid %s of size %ld</what>\n",
|
|
readwrite(xe->XE.Heap.sszB),
|
|
Word__abs(xe->XE.Heap.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " <auxwhat>Address %#lx is not derived from "
|
|
"any known block</auxwhat>\n", a );
|
|
|
|
} else {
|
|
|
|
emit( "Invalid %s of size %ld\n",
|
|
readwrite(xe->XE.Heap.sszB),
|
|
Word__abs(xe->XE.Heap.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " Address %#lx is not derived from "
|
|
"any known block\n", a );
|
|
|
|
}
|
|
|
|
} else {
|
|
// Access via a pointer, but outside its range.
|
|
Int cmp;
|
|
UWord miss_size;
|
|
Seg__cmp(vseg, a, &cmp, &miss_size);
|
|
if (cmp < 0) place = "before";
|
|
else if (cmp == 0) place = "inside";
|
|
else place = "after";
|
|
how_invalid = ( ( Seg__is_freed(vseg) && 0 != cmp )
|
|
? "Doubly-invalid" : "Invalid" );
|
|
legit = ( Seg__is_freed(vseg) ? "once-" : "" );
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>%s %s of size %ld</what>\n",
|
|
how_invalid,
|
|
readwrite(xe->XE.Heap.sszB),
|
|
Word__abs(xe->XE.Heap.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " <auxwhat>Address %#lx is %lu bytes %s "
|
|
"the accessing pointer's</auxwhat>\n",
|
|
a, miss_size, place );
|
|
emit( " <auxwhat>%slegitimate range, "
|
|
"a block of size %lu %s</auxwhat>\n",
|
|
legit, Seg__size(vseg),
|
|
Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
|
|
VG_(pp_ExeContext)(Seg__where(vseg));
|
|
|
|
} else {
|
|
|
|
emit( "%s %s of size %ld\n",
|
|
how_invalid,
|
|
readwrite(xe->XE.Heap.sszB),
|
|
Word__abs(xe->XE.Heap.sszB) );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
|
|
a, miss_size, place );
|
|
emit( " %slegitimate range, a block of size %lu %s\n",
|
|
legit, Seg__size(vseg),
|
|
Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
|
|
VG_(pp_ExeContext)(Seg__where(vseg));
|
|
|
|
}
|
|
}
|
|
|
|
/* If we have a better description of the address, show it.
|
|
Note that in XML mode, it will already by nicely wrapped up
|
|
in tags, either <auxwhat> or <xauxwhat>, so we can just emit
|
|
it verbatim. */
|
|
if (xml) {
|
|
|
|
if (xe->XE.Heap.descr1)
|
|
emiN( " %pS\n",
|
|
(HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
|
|
if (xe->XE.Heap.descr2)
|
|
emiN( " %pS\n",
|
|
(HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
|
|
if (xe->XE.Heap.datasym[0] != 0)
|
|
emiN( " <auxwhat>Address 0x%llx is %llu bytes "
|
|
"inside data symbol \"%pS\"</auxwhat>\n",
|
|
(ULong)xe->XE.Heap.addr,
|
|
(ULong)xe->XE.Heap.datasymoff,
|
|
xe->XE.Heap.datasym );
|
|
|
|
} else {
|
|
|
|
if (xe->XE.Heap.descr1)
|
|
emit( " %s\n",
|
|
(HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
|
|
if (xe->XE.Heap.descr2)
|
|
emit( " %s\n",
|
|
(HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
|
|
if (xe->XE.Heap.datasym[0] != 0)
|
|
emit( " Address 0x%llx is %llu bytes "
|
|
"inside data symbol \"%s\"\n",
|
|
(ULong)xe->XE.Heap.addr,
|
|
(ULong)xe->XE.Heap.datasymoff,
|
|
xe->XE.Heap.datasym );
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
case XE_Arith: {
|
|
Seg* seg1 = xe->XE.Arith.seg1;
|
|
Seg* seg2 = xe->XE.Arith.seg2;
|
|
const HChar* which;
|
|
|
|
tl_assert(BOTTOM != seg1);
|
|
tl_assert(BOTTOM != seg2 && UNKNOWN != seg2);
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>Invalid arguments to %s</what>\n",
|
|
xe->XE.Arith.opname );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
if (seg1 != seg2) {
|
|
if (NONPTR == seg1) {
|
|
emit( " <auxwhat>First arg not a pointer</auxwhat>\n" );
|
|
} else if (UNKNOWN == seg1) {
|
|
emit( " <auxwhat>First arg may be a pointer</auxwhat>\n" );
|
|
} else {
|
|
emit( " <auxwhat>First arg derived from address %#lx of "
|
|
"%lu-byte block alloc'd</auxwhat>\n",
|
|
Seg__addr(seg1), Seg__size(seg1) );
|
|
VG_(pp_ExeContext)(Seg__where(seg1));
|
|
}
|
|
which = "Second arg";
|
|
} else {
|
|
which = "Both args";
|
|
}
|
|
if (NONPTR == seg2) {
|
|
emit( " <auxwhat>%s not a pointer</auxwhat>\n", which );
|
|
} else {
|
|
emit( " <auxwhat>%s derived from address %#lx of "
|
|
"%lu-byte block alloc'd</auxwhat>\n",
|
|
which, Seg__addr(seg2), Seg__size(seg2) );
|
|
VG_(pp_ExeContext)(Seg__where(seg2));
|
|
}
|
|
|
|
} else {
|
|
|
|
emit( "Invalid arguments to %s\n",
|
|
xe->XE.Arith.opname );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
if (seg1 != seg2) {
|
|
if (NONPTR == seg1) {
|
|
emit( " First arg not a pointer\n" );
|
|
} else if (UNKNOWN == seg1) {
|
|
emit( " First arg may be a pointer\n" );
|
|
} else {
|
|
emit( " First arg derived from address %#lx of "
|
|
"%lu-byte block alloc'd\n",
|
|
Seg__addr(seg1), Seg__size(seg1) );
|
|
VG_(pp_ExeContext)(Seg__where(seg1));
|
|
}
|
|
which = "Second arg";
|
|
} else {
|
|
which = "Both args";
|
|
}
|
|
if (NONPTR == seg2) {
|
|
emit( " %s not a pointer\n", which );
|
|
} else {
|
|
emit( " %s derived from address %#lx of "
|
|
"%lu-byte block alloc'd\n",
|
|
which, Seg__addr(seg2), Seg__size(seg2) );
|
|
VG_(pp_ExeContext)(Seg__where(seg2));
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
case XE_SysParam: {
|
|
Addr lo = xe->XE.SysParam.lo;
|
|
Addr hi = xe->XE.SysParam.hi;
|
|
Seg* seglo = xe->XE.SysParam.seglo;
|
|
Seg* seghi = xe->XE.SysParam.seghi;
|
|
const HChar* s = VG_(get_error_string) (err);
|
|
const HChar* what;
|
|
|
|
tl_assert(BOTTOM != seglo && BOTTOM != seghi);
|
|
|
|
if (Vg_CoreSysCall == xe->XE.SysParam.part)
|
|
what = "Syscall param ";
|
|
else VG_(tool_panic)("bad CorePart");
|
|
|
|
if (seglo == seghi) {
|
|
// freed block
|
|
tl_assert(is_known_segment(seglo));
|
|
tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled?
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>%s%s contains unaddressable byte(s)</what>\n",
|
|
what, s );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " <auxwhat>Address %#lx is %lu bytes inside a "
|
|
"%lu-byte block free'd</auxwhat>\n",
|
|
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
|
VG_(pp_ExeContext)(Seg__where(seglo));
|
|
|
|
} else {
|
|
|
|
emit( " %s%s contains unaddressable byte(s)\n",
|
|
what, s );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
emit( " Address %#lx is %lu bytes inside a "
|
|
"%lu-byte block free'd\n",
|
|
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
|
VG_(pp_ExeContext)(Seg__where(seglo));
|
|
|
|
}
|
|
|
|
} else {
|
|
// mismatch
|
|
|
|
if (xml) {
|
|
|
|
emit( " <what>%s%s is non-contiguous</what>\n",
|
|
what, s );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
if (UNKNOWN == seglo) {
|
|
emit( " <auxwhat>First byte is "
|
|
"not inside a known block</auxwhat>\n" );
|
|
} else {
|
|
emit( " <auxwhat>First byte (%#lx) is %lu bytes inside a "
|
|
"%lu-byte block alloc'd</auxwhat>\n",
|
|
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
|
VG_(pp_ExeContext)(Seg__where(seglo));
|
|
}
|
|
|
|
if (UNKNOWN == seghi) {
|
|
emit( " <auxwhat>Last byte is "
|
|
"not inside a known block</auxwhat>\n" );
|
|
} else {
|
|
emit( " <auxwhat>Last byte (%#lx) is %lu bytes inside a "
|
|
"%lu-byte block alloc'd</auxwhat>\n",
|
|
hi, hi-Seg__addr(seghi), Seg__size(seghi) );
|
|
VG_(pp_ExeContext)(Seg__where(seghi));
|
|
}
|
|
|
|
} else {
|
|
|
|
emit( "%s%s is non-contiguous\n",
|
|
what, s );
|
|
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
|
|
|
if (UNKNOWN == seglo) {
|
|
emit( " First byte is not inside a known block\n" );
|
|
} else {
|
|
emit( " First byte (%#lx) is %lu bytes inside a "
|
|
"%lu-byte block alloc'd\n",
|
|
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
|
VG_(pp_ExeContext)(Seg__where(seglo));
|
|
}
|
|
|
|
if (UNKNOWN == seghi) {
|
|
emit( " Last byte is not inside a known block\n" );
|
|
} else {
|
|
emit( " Last byte (%#lx) is %lu bytes inside a "
|
|
"%lu-byte block alloc'd\n",
|
|
hi, hi-Seg__addr(seghi), Seg__size(seghi) );
|
|
VG_(pp_ExeContext)(Seg__where(seghi));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
VG_(tool_panic)("pp_Error: unrecognised error kind");
|
|
}
|
|
}
|
|
|
|
|
|
UInt pc_update_Error_extra ( const Error* err )
|
|
{
|
|
XError *xe = (XError*)VG_(get_error_extra)(err);
|
|
tl_assert(xe);
|
|
switch (xe->tag) {
|
|
case XE_SorG:
|
|
break;
|
|
case XE_Heap: {
|
|
Bool have_descr;
|
|
|
|
xe->XE.Heap.datasymoff = 0;
|
|
xe->XE.Heap.datasym = NULL;
|
|
|
|
tl_assert(!xe->XE.Heap.descr1);
|
|
tl_assert(!xe->XE.Heap.descr2);
|
|
|
|
xe->XE.Heap.descr1
|
|
= VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
|
|
VG_(free), sizeof(HChar) );
|
|
xe->XE.Heap.descr2
|
|
= VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
|
|
VG_(free), sizeof(HChar) );
|
|
|
|
xe->XE.Heap.datasymoff = 0;
|
|
|
|
have_descr
|
|
= VG_(get_data_description)( xe->XE.Heap.descr1,
|
|
xe->XE.Heap.descr2,
|
|
xe->XE.Heap.addr );
|
|
|
|
/* If there's nothing in descr1/2, free it. Why is it safe to
|
|
to VG_(indexXA) at zero here? Because
|
|
VG_(get_data_description) guarantees to zero terminate
|
|
descr1/2 regardless of the outcome of the call. So there's
|
|
always at least one element in each XA after the call.
|
|
*/
|
|
if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr1, 0 ))
|
|
|| !have_descr) {
|
|
VG_(deleteXA)( xe->XE.Heap.descr1 );
|
|
xe->XE.Heap.descr1 = NULL;
|
|
}
|
|
if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr2, 0 ))
|
|
|| !have_descr) {
|
|
VG_(deleteXA)( xe->XE.Heap.descr2 );
|
|
xe->XE.Heap.descr2 = NULL;
|
|
}
|
|
|
|
/* If Dwarf3 info produced nothing useful, see at least if
|
|
we can fish something useful out of the ELF symbol info. */
|
|
if (!have_descr) {
|
|
const HChar *name;
|
|
if (VG_(get_datasym_and_offset)(
|
|
xe->XE.Heap.addr, &name,
|
|
&xe->XE.Heap.datasymoff )
|
|
) {
|
|
xe->XE.Heap.datasym =
|
|
VG_(strdup)("pc.update_extra.Heap.datasym", name);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case XE_Arith:
|
|
break;
|
|
case XE_SysParam:
|
|
break;
|
|
default:
|
|
VG_(tool_panic)("update_extra");
|
|
}
|
|
return sizeof(XError);
|
|
}
|
|
|
|
Bool pc_is_recognised_suppression ( const HChar* name, Supp *su )
|
|
{
|
|
SuppKind skind;
|
|
|
|
if (VG_STREQ(name, "SorG")) skind = XS_SorG;
|
|
else if (VG_STREQ(name, "Heap")) skind = XS_Heap;
|
|
else if (VG_STREQ(name, "Arith")) skind = XS_Arith;
|
|
else if (VG_STREQ(name, "SysParam")) skind = XS_SysParam;
|
|
else
|
|
return False;
|
|
|
|
VG_(set_supp_kind)(su, skind);
|
|
return True;
|
|
}
|
|
|
|
Bool pc_read_extra_suppression_info ( Int fd, HChar** bufpp,
|
|
SizeT* nBufp, Int* lineno,
|
|
Supp* su )
|
|
{
|
|
Bool eof;
|
|
if (VG_(get_supp_kind)(su) == XS_SysParam) {
|
|
eof = VG_(get_line) ( fd, bufpp, nBufp, lineno );
|
|
if (eof) return False;
|
|
VG_(set_supp_string)(su, VG_(strdup)("pc.common.presi.1", *bufpp));
|
|
}
|
|
return True;
|
|
}
|
|
|
|
Bool pc_error_matches_suppression (const Error* err, const Supp* su)
|
|
{
|
|
ErrorKind ekind = VG_(get_error_kind)(err);
|
|
switch (VG_(get_supp_kind)(su)) {
|
|
case XS_SorG: return ekind == XE_SorG;
|
|
case XS_Heap: return ekind == XE_Heap;
|
|
case XS_Arith: return ekind == XE_Arith;
|
|
case XS_SysParam: return ekind == XE_SysParam;
|
|
default:
|
|
VG_(printf)("Error:\n"
|
|
" unknown suppression type %d\n",
|
|
VG_(get_supp_kind)(su));
|
|
VG_(tool_panic)("unknown suppression type in "
|
|
"pc_error_matches_suppression");
|
|
}
|
|
}
|
|
|
|
const HChar* pc_get_error_name ( const Error* err )
|
|
{
|
|
XError *xe = (XError*)VG_(get_error_extra)(err);
|
|
tl_assert(xe);
|
|
switch (xe->tag) {
|
|
case XE_SorG: return "SorG";
|
|
case XE_Heap: return "Heap";
|
|
case XE_Arith: return "Arith";
|
|
case XE_SysParam: return "SysParam";
|
|
default: VG_(tool_panic)("get_error_name: unexpected type");
|
|
}
|
|
}
|
|
|
|
SizeT pc_get_extra_suppression_info ( const Error* err,
|
|
/*OUT*/HChar* buf, Int nBuf )
|
|
{
|
|
ErrorKind ekind = VG_(get_error_kind )(err);
|
|
tl_assert(buf);
|
|
tl_assert(nBuf >= 1);
|
|
|
|
if (XE_SysParam == ekind) {
|
|
const HChar* errstr = VG_(get_error_string)(err);
|
|
tl_assert(errstr);
|
|
return VG_(snprintf)(buf, nBuf, "%s", errstr);
|
|
} else {
|
|
buf[0] = '\0';
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
SizeT pc_print_extra_suppression_use ( const Supp* su,
|
|
/*OUT*/HChar* buf, Int nBuf )
|
|
{
|
|
tl_assert(nBuf >= 1);
|
|
buf[0] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
void pc_update_extra_suppression_use (const Error* err, const Supp* su)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end pc_common.c ---*/
|
|
/*--------------------------------------------------------------------*/
|