mirror of
git://sourceware.org/git/valgrind.git
synced 2026-01-12 00:19:31 +08:00
Factorises the address code description and printing
of memcheck and helgrind in a common module: pub_tool_addrinfo.h pub_core_addrinfo.h m_addrinfo.c At the same time, the factorised code is made usable by other tools also (and is used by the gdbserver command 'v.info location' which replaces the helgrind 'describe addr' introduced 1 week ago and which is now callable by all tools). The new address description code can describe more addresses (e.g. for memcheck, if the block is not on the free list anymore, but is in an arena free list, this will also be described). Similarly, helgrind address description can now describe more addresses when --read-var-info=no is given (e.g. global symbols are described, or addresses on the stack are described as being on the stack, freed blocks in the arena free list are described, ...). See e.g. the change in helgrind/tests/annotate_rwlock.stderr.exp or locked_vs_unlocked2.stderr.exp The patch touches many files, but is basically a lot of improvements in helgrind output files. The code changes are mostly refactorisation of existing code. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13965
This commit is contained in:
8
NEWS
8
NEWS
@@ -15,8 +15,6 @@ Release 3.10.0 (?? ?????? 201?)
|
||||
VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE
|
||||
|
||||
* Helgrind:
|
||||
- Helgrind GDB server monitor command 'describe <address>'
|
||||
allowing to describe an address (e.g. where it was allocated).
|
||||
- Helgrind GDB server monitor command 'info locks' giving
|
||||
the list of locks, their location, and their status.
|
||||
|
||||
@@ -28,6 +26,12 @@ Release 3.10.0 (?? ?????? 201?)
|
||||
|
||||
* New and modified GDB server monitor features:
|
||||
|
||||
- The GDB server monitor command 'v.info location <address>'
|
||||
outputs information about an address. The information produced depends
|
||||
on the tool and on the options given to valgrind.
|
||||
Possibly, the following are described: global variables, local (stack)
|
||||
variables, allocated or freed blocks, ...
|
||||
|
||||
- The option "--vgdb-stop-at=event1,event2,..." allows the user
|
||||
to ask GDB server to stop before program execution, at the end
|
||||
of the program execution and on Valgrind internal errors.
|
||||
|
||||
@@ -158,6 +158,7 @@ $(mach_hdrs): $(mach_defs) $(mach_user_srcs) $(abs_builddir)/m_mach
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_HEADERS = \
|
||||
pub_core_addrinfo.h \
|
||||
pub_core_aspacehl.h \
|
||||
pub_core_aspacemgr.h \
|
||||
pub_core_basics.h \
|
||||
@@ -271,6 +272,7 @@ pkglib_LIBRARIES += libcoregrind-@VGCONF_ARCH_SEC@-@VGCONF_OS@.a
|
||||
endif
|
||||
|
||||
COREGRIND_SOURCES_COMMON = \
|
||||
m_addrinfo.c \
|
||||
m_cache.c \
|
||||
m_commandline.c \
|
||||
m_clientstate.c \
|
||||
|
||||
354
coregrind/m_addrinfo.c
Normal file
354
coregrind/m_addrinfo.c
Normal file
@@ -0,0 +1,354 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Obtaining information about an address. ---*/
|
||||
/*--- m_addrinfo.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2008-2013 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.
|
||||
*/
|
||||
|
||||
#include "pub_core_basics.h"
|
||||
#include "pub_core_libcassert.h"
|
||||
#include "pub_core_libcbase.h"
|
||||
#include "pub_core_libcprint.h"
|
||||
#include "pub_core_xarray.h"
|
||||
#include "pub_core_debuginfo.h"
|
||||
#include "pub_core_execontext.h"
|
||||
#include "pub_core_addrinfo.h"
|
||||
#include "pub_core_mallocfree.h"
|
||||
#include "pub_core_machine.h"
|
||||
#include "pub_core_options.h"
|
||||
|
||||
void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
|
||||
{
|
||||
ThreadId tid;
|
||||
Addr stack_min, stack_max;
|
||||
VgSectKind sect;
|
||||
|
||||
/* -- Perhaps the variable type/location data describes it? -- */
|
||||
ai->Addr.Variable.descr1
|
||||
= VG_(newXA)( VG_(malloc), "mc.da.descr1",
|
||||
VG_(free), sizeof(HChar) );
|
||||
ai->Addr.Variable.descr2
|
||||
= VG_(newXA)( VG_(malloc), "mc.da.descr2",
|
||||
VG_(free), sizeof(HChar) );
|
||||
|
||||
(void) VG_(get_data_description)( ai->Addr.Variable.descr1,
|
||||
ai->Addr.Variable.descr2, a );
|
||||
/* If there's nothing in descr1/2, free them. 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)( ai->Addr.Variable.descr1, 0 ))) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr1 );
|
||||
ai->Addr.Variable.descr1 = NULL;
|
||||
}
|
||||
if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr2 );
|
||||
ai->Addr.Variable.descr2 = NULL;
|
||||
}
|
||||
/* Assume (assert) that VG_(get_data_description) fills in descr1
|
||||
before it fills in descr2 */
|
||||
if (ai->Addr.Variable.descr1 == NULL)
|
||||
vg_assert(ai->Addr.Variable.descr2 == NULL);
|
||||
/* So did we get lucky? */
|
||||
if (ai->Addr.Variable.descr1 != NULL) {
|
||||
ai->tag = Addr_Variable;
|
||||
return;
|
||||
}
|
||||
/* -- Have a look at the low level data symbols - perhaps it's in
|
||||
there. -- */
|
||||
VG_(memset)( &ai->Addr.DataSym.name,
|
||||
0, sizeof(ai->Addr.DataSym.name));
|
||||
if (VG_(get_datasym_and_offset)(
|
||||
a, &ai->Addr.DataSym.name[0],
|
||||
sizeof(ai->Addr.DataSym.name)-1,
|
||||
&ai->Addr.DataSym.offset )) {
|
||||
ai->tag = Addr_DataSym;
|
||||
vg_assert( ai->Addr.DataSym.name
|
||||
[ sizeof(ai->Addr.DataSym.name)-1 ] == 0);
|
||||
return;
|
||||
}
|
||||
/* -- Perhaps it's on a thread's stack? -- */
|
||||
VG_(thread_stack_reset_iter)(&tid);
|
||||
while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
|
||||
if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
|
||||
ai->tag = Addr_Stack;
|
||||
ai->Addr.Stack.tid = tid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Maybe it is in one of the m_mallocfree.c arenas. -- */
|
||||
{
|
||||
AddrArenaInfo aai;
|
||||
VG_(describe_arena_addr) ( a, &aai );
|
||||
if (aai.name != NULL) {
|
||||
ai->tag = Addr_Block;
|
||||
if (aai.aid == VG_AR_CLIENT)
|
||||
ai->Addr.Block.block_kind
|
||||
= aai.free ? Block_ClientArenaFree : Block_ClientArenaMallocd;
|
||||
else
|
||||
ai->Addr.Block.block_kind
|
||||
= aai.free
|
||||
? Block_ValgrindArenaFree : Block_ValgrindArenaMallocd;
|
||||
ai->Addr.Block.block_desc = aai.name;
|
||||
ai->Addr.Block.block_szB = aai.block_szB;
|
||||
ai->Addr.Block.rwoffset = aai.rwoffset;
|
||||
ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
|
||||
ai->Addr.Block.freed_at = VG_(null_ExeContext)();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* -- last ditch attempt at classification -- */
|
||||
vg_assert( sizeof(ai->Addr.SectKind.objname) > 4 );
|
||||
VG_(memset)( &ai->Addr.SectKind.objname,
|
||||
0, sizeof(ai->Addr.SectKind.objname));
|
||||
VG_(strcpy)( ai->Addr.SectKind.objname, "???" );
|
||||
sect = VG_(DebugInfo_sect_kind)( &ai->Addr.SectKind.objname[0],
|
||||
sizeof(ai->Addr.SectKind.objname)-1, a);
|
||||
if (sect != Vg_SectUnknown) {
|
||||
ai->tag = Addr_SectKind;
|
||||
ai->Addr.SectKind.kind = sect;
|
||||
vg_assert( ai->Addr.SectKind.objname
|
||||
[ sizeof(ai->Addr.SectKind.objname)-1 ] == 0);
|
||||
return;
|
||||
}
|
||||
/* -- Clueless ... -- */
|
||||
ai->tag = Addr_Unknown;
|
||||
return;
|
||||
}
|
||||
|
||||
void VG_(clear_addrinfo) ( AddrInfo* ai)
|
||||
{
|
||||
switch (ai->tag) {
|
||||
case Addr_Unknown:
|
||||
break;
|
||||
|
||||
case Addr_Stack:
|
||||
break;
|
||||
|
||||
case Addr_Block:
|
||||
break;
|
||||
|
||||
case Addr_DataSym:
|
||||
break;
|
||||
|
||||
case Addr_Variable:
|
||||
if (ai->Addr.Variable.descr1 != NULL) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr1 );
|
||||
ai->Addr.Variable.descr1 = NULL;
|
||||
}
|
||||
if (ai->Addr.Variable.descr2 != NULL) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr2 );
|
||||
ai->Addr.Variable.descr2 = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case Addr_SectKind:
|
||||
break;
|
||||
|
||||
default:
|
||||
VG_(core_panic)("VG_(clear_addrinfo)");
|
||||
}
|
||||
|
||||
ai->tag = Addr_Undescribed;
|
||||
}
|
||||
|
||||
static Bool is_arena_BlockKind(BlockKind bk)
|
||||
{
|
||||
switch (bk) {
|
||||
case Block_Mallocd:
|
||||
case Block_Freed:
|
||||
case Block_MempoolChunk:
|
||||
case Block_UserG: return False;
|
||||
|
||||
case Block_ClientArenaMallocd:
|
||||
case Block_ClientArenaFree:
|
||||
case Block_ValgrindArenaMallocd:
|
||||
case Block_ValgrindArenaFree: return True;
|
||||
|
||||
default: vg_assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_addrinfo_WRK ( Addr a, AddrInfo* ai, Bool mc, Bool maybe_gcc )
|
||||
{
|
||||
const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
|
||||
const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
|
||||
|
||||
vg_assert (!maybe_gcc || mc); // maybe_gcc can only be given in mc mode.
|
||||
|
||||
switch (ai->tag) {
|
||||
case Addr_Unknown:
|
||||
if (maybe_gcc) {
|
||||
VG_(emit)( "%sAddress 0x%llx is just below the stack ptr. "
|
||||
"To suppress, use: --workaround-gcc296-bugs=yes%s\n",
|
||||
xpre, (ULong)a, xpost );
|
||||
} else {
|
||||
VG_(emit)( "%sAddress 0x%llx "
|
||||
"is not stack'd, malloc'd or %s%s\n",
|
||||
xpre,
|
||||
(ULong)a,
|
||||
mc ? "(recently) free'd" : "on a free list",
|
||||
xpost );
|
||||
}
|
||||
break;
|
||||
|
||||
case Addr_Stack:
|
||||
VG_(emit)( "%sAddress 0x%llx is on thread %d's stack%s\n",
|
||||
xpre, (ULong)a, ai->Addr.Stack.tid, xpost );
|
||||
break;
|
||||
|
||||
case Addr_Block: {
|
||||
SizeT block_szB = ai->Addr.Block.block_szB;
|
||||
PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
|
||||
SizeT delta;
|
||||
const HChar* relative;
|
||||
|
||||
if (rwoffset < 0) {
|
||||
delta = (SizeT)(-rwoffset);
|
||||
relative = "before";
|
||||
} else if (rwoffset >= block_szB) {
|
||||
delta = rwoffset - block_szB;
|
||||
relative = "after";
|
||||
} else {
|
||||
delta = rwoffset;
|
||||
relative = "inside";
|
||||
}
|
||||
if (is_arena_BlockKind (ai->Addr.Block.block_kind))
|
||||
VG_(emit)(
|
||||
"%sAddress 0x%lx is %'lu bytes %s a%s block of size %'lu"
|
||||
" in arena \"%s\"%s\n",
|
||||
xpre,
|
||||
a, delta,
|
||||
relative,
|
||||
ai->Addr.Block.block_kind==Block_ClientArenaMallocd
|
||||
|| ai->Addr.Block.block_kind==Block_ValgrindArenaMallocd
|
||||
? "" : "n unallocated",
|
||||
block_szB,
|
||||
ai->Addr.Block.block_desc, // arena name
|
||||
xpost
|
||||
);
|
||||
else
|
||||
VG_(emit)(
|
||||
"%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
|
||||
xpre,
|
||||
a, delta,
|
||||
relative,
|
||||
ai->Addr.Block.block_desc,
|
||||
block_szB,
|
||||
ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
|
||||
: ai->Addr.Block.block_kind==Block_Freed ? "free'd"
|
||||
: "client-defined",
|
||||
xpost
|
||||
);
|
||||
if (ai->Addr.Block.block_kind==Block_Mallocd) {
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
|
||||
}
|
||||
else if (ai->Addr.Block.block_kind==Block_Freed) {
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
|
||||
if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
|
||||
VG_(emit)(
|
||||
"%s block was alloc'd at%s\n",
|
||||
xpre,
|
||||
xpost
|
||||
);
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
}
|
||||
}
|
||||
else if (ai->Addr.Block.block_kind==Block_MempoolChunk
|
||||
|| ai->Addr.Block.block_kind==Block_UserG) {
|
||||
// client-defined
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
|
||||
/* Nb: cannot have a freed_at, as a freed client-defined block
|
||||
has a Block_Freed block_kind. */
|
||||
} else {
|
||||
// Client or Valgrind arena. At least currently, we never
|
||||
// have stacktraces for these.
|
||||
tl_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
|
||||
tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Addr_DataSym:
|
||||
VG_(emit)( "%sAddress 0x%llx is %llu bytes "
|
||||
"inside data symbol \"%pS\"%s\n",
|
||||
xpre,
|
||||
(ULong)a,
|
||||
(ULong)ai->Addr.DataSym.offset,
|
||||
ai->Addr.DataSym.name,
|
||||
xpost );
|
||||
break;
|
||||
|
||||
case Addr_Variable:
|
||||
/* Note, no need for XML tags here, because descr1/2 will
|
||||
already have <auxwhat> or <xauxwhat>s on them, in XML
|
||||
mode. */
|
||||
if (ai->Addr.Variable.descr1)
|
||||
VG_(emit)( "%s%s\n",
|
||||
VG_(clo_xml) ? " " : " ",
|
||||
(HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
|
||||
if (ai->Addr.Variable.descr2)
|
||||
VG_(emit)( "%s%s\n",
|
||||
VG_(clo_xml) ? " " : " ",
|
||||
(HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
|
||||
break;
|
||||
|
||||
case Addr_SectKind:
|
||||
VG_(emit)( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
|
||||
xpre,
|
||||
(ULong)a,
|
||||
VG_(pp_SectKind)(ai->Addr.SectKind.kind),
|
||||
ai->Addr.SectKind.objname,
|
||||
xpost );
|
||||
break;
|
||||
|
||||
default:
|
||||
VG_(tool_panic)("mc_pp_AddrInfo");
|
||||
}
|
||||
}
|
||||
|
||||
void VG_(pp_addrinfo) ( Addr a, AddrInfo* ai )
|
||||
{
|
||||
pp_addrinfo_WRK (a, ai, False /*mc*/, False /*maybe_gcc*/);
|
||||
}
|
||||
|
||||
void VG_(pp_addrinfo_mc) ( Addr a, AddrInfo* ai, Bool maybe_gcc )
|
||||
{
|
||||
pp_addrinfo_WRK (a, ai, True /*mc*/, maybe_gcc);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end m_addrinfo.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -1404,7 +1404,7 @@ static Bool is_zero_b (const HChar *s)
|
||||
return False;
|
||||
}
|
||||
|
||||
void VG_(strtok_get_address_and_size) (Addr* address,
|
||||
Bool VG_(strtok_get_address_and_size) (Addr* address,
|
||||
SizeT* szB,
|
||||
HChar **ssaveptr)
|
||||
{
|
||||
@@ -1419,7 +1419,7 @@ void VG_(strtok_get_address_and_size) (Addr* address,
|
||||
VG_(gdb_printf) ("missing or malformed address\n");
|
||||
*address = (Addr) 0;
|
||||
*szB = 0;
|
||||
return;
|
||||
return False;
|
||||
}
|
||||
ws = VG_(strtok_r) (NULL, " ", ssaveptr);
|
||||
if (ws == NULL) {
|
||||
@@ -1451,8 +1451,9 @@ void VG_(strtok_get_address_and_size) (Addr* address,
|
||||
"hex 0x..... or dec ...... or binary .....b\n");
|
||||
*address = (Addr) 0;
|
||||
*szB = 0;
|
||||
return;
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
void VG_(gdbserver_status_output)(void)
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "pub_core_syswrap.h" // VG_(show_open_fds)
|
||||
#include "pub_core_scheduler.h"
|
||||
#include "pub_core_transtab.h"
|
||||
#include "pub_core_debuginfo.h"
|
||||
#include "pub_core_addrinfo.h"
|
||||
|
||||
unsigned long cont_thread;
|
||||
unsigned long general_thread;
|
||||
@@ -224,6 +226,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return)
|
||||
" v.wait [<ms>] : sleep <ms> (default 0) then continue\n"
|
||||
" v.info all_errors : show all errors found so far\n"
|
||||
" v.info last_error : show last error found\n"
|
||||
" v.info location <addr> : show information about location <addr>\n"
|
||||
" v.info n_errs_found [msg] : show the nr of errors found so far and the given msg\n"
|
||||
" v.info open_fds : show open file descriptors (only if --track-fds=yes)\n"
|
||||
" v.kill : kill the Valgrind process\n"
|
||||
@@ -341,7 +344,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return)
|
||||
wcmd = strtok_r (NULL, " ", &ssaveptr);
|
||||
switch (kwdid = VG_(keyword_id)
|
||||
("all_errors n_errs_found last_error gdbserver_status memory"
|
||||
" scheduler stats open_fds exectxt",
|
||||
" scheduler stats open_fds exectxt location",
|
||||
wcmd, kwd_report_all)) {
|
||||
case -2:
|
||||
case -1:
|
||||
@@ -407,6 +410,31 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return)
|
||||
VG_(print_ExeContext_stats) (True /* with_stacktraces */);
|
||||
ret = 1;
|
||||
break;
|
||||
case 9: { /* location */
|
||||
/* Note: we prefer 'v.info location' and not 'v.info address' as
|
||||
v.info address is inconsistent with the GDB (native)
|
||||
command 'info address' which gives the address for a symbol.
|
||||
GDB equivalent command of 'v.info location' is 'info symbol'. */
|
||||
Addr address;
|
||||
SizeT dummy_sz = 0x1234;
|
||||
if (VG_(strtok_get_address_and_size) (&address, &dummy_sz, &ssaveptr)) {
|
||||
// If tool provides location information, use that.
|
||||
if (VG_(needs).info_location) {
|
||||
VG_TDICT_CALL(tool_info_location, address);
|
||||
}
|
||||
// If tool does not provide location information, use the common one.
|
||||
// Also use the common to compare with tool when debug log is set.
|
||||
if (!VG_(needs).info_location || VG_(debugLog_getLevel)() > 0 ) {
|
||||
AddrInfo ai;
|
||||
ai.tag = Addr_Undescribed;
|
||||
VG_(describe_addr) (address, &ai);
|
||||
VG_(pp_addrinfo) (address, &ai);
|
||||
VG_(clear_addrinfo) (&ai);
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vg_assert(0);
|
||||
}
|
||||
@@ -431,8 +459,7 @@ int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return)
|
||||
|
||||
ret = 1;
|
||||
|
||||
VG_(strtok_get_address_and_size) (&address, &verbosity, &ssaveptr);
|
||||
if (address != (Addr) 0 || verbosity != 0) {
|
||||
if (VG_(strtok_get_address_and_size) (&address, &verbosity, &ssaveptr)) {
|
||||
/* we need to force the output to log for the translation trace,
|
||||
as low level VEX tracing cannot be redirected to gdb. */
|
||||
int saved_command_output_to_log = command_output_to_log;
|
||||
|
||||
@@ -168,6 +168,25 @@ UInt VG_(printf_xml) ( const HChar *format, ... )
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UInt emit_WRK ( const HChar* format, va_list vargs )
|
||||
{
|
||||
if (VG_(clo_xml)) {
|
||||
return VG_(vprintf_xml)(format, vargs);
|
||||
} else if (VG_(log_output_sink).fd == -2) {
|
||||
return VG_(vprintf) (format, vargs);
|
||||
} else {
|
||||
return VG_(vmessage)(Vg_UserMsg, format, vargs);
|
||||
}
|
||||
}
|
||||
UInt VG_(emit) ( const HChar* format, ... )
|
||||
{
|
||||
UInt ret;
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
ret = emit_WRK(format, vargs);
|
||||
va_end(vargs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------- sprintf --------- */
|
||||
|
||||
|
||||
@@ -943,6 +943,33 @@ Superblock* findSb ( Arena* a, Block* b )
|
||||
}
|
||||
|
||||
|
||||
// Find the superblock containing the given address.
|
||||
// If superblock not found, return NULL.
|
||||
static
|
||||
Superblock* maybe_findSb ( Arena* a, Addr ad )
|
||||
{
|
||||
SizeT min = 0;
|
||||
SizeT max = a->sblocks_used;
|
||||
|
||||
while (min <= max) {
|
||||
Superblock * sb;
|
||||
SizeT pos = min + (max - min)/2;
|
||||
if (pos < 0 || pos >= a->sblocks_used)
|
||||
return NULL;
|
||||
sb = a->sblocks[pos];
|
||||
if ((Addr)&sb->payload_bytes[0] <= ad
|
||||
&& ad < (Addr)&sb->payload_bytes[sb->n_payload_bytes]) {
|
||||
return sb;
|
||||
} else if ((Addr)&sb->payload_bytes[0] <= ad) {
|
||||
min = pos + 1;
|
||||
} else {
|
||||
max = pos - 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Functions for working with freelists. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
@@ -1413,6 +1440,43 @@ void VG_(sanity_check_malloc_all) ( void )
|
||||
}
|
||||
}
|
||||
|
||||
void VG_(describe_arena_addr) ( Addr a, AddrArenaInfo* aai )
|
||||
{
|
||||
UInt i;
|
||||
Superblock *sb;
|
||||
Arena *arena;
|
||||
|
||||
for (i = 0; i < VG_N_ARENAS; i++) {
|
||||
if (i == VG_AR_CLIENT && !client_inited)
|
||||
continue;
|
||||
arena = arenaId_to_ArenaP(i);
|
||||
sb = maybe_findSb( arena, a );
|
||||
if (sb != NULL) {
|
||||
Word j;
|
||||
SizeT b_bszB;
|
||||
Block *b = NULL;
|
||||
|
||||
aai->aid = i;
|
||||
aai->name = arena->name;
|
||||
for (j = 0; j < sb->n_payload_bytes; j += mk_plain_bszB(b_bszB)) {
|
||||
b = (Block*)&sb->payload_bytes[j];
|
||||
b_bszB = get_bszB_as_is(b);
|
||||
if (a < (Addr)b + mk_plain_bszB(b_bszB))
|
||||
break;
|
||||
}
|
||||
vg_assert (b);
|
||||
aai->block_szB = get_pszB(arena, b);
|
||||
aai->rwoffset = a - (Addr)get_block_payload(arena, b);
|
||||
aai->free = !is_inuse_block(b);
|
||||
return;
|
||||
}
|
||||
}
|
||||
aai->aid = 0;
|
||||
aai->name = NULL;
|
||||
aai->block_szB = 0;
|
||||
aai->rwoffset = 0;
|
||||
aai->free = False;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Creating and deleting blocks. ---*/
|
||||
|
||||
@@ -93,6 +93,7 @@ VgNeeds VG_(needs) = {
|
||||
.syscall_wrapper = False,
|
||||
.sanity_checks = False,
|
||||
.print_stats = False,
|
||||
.info_location = False,
|
||||
.var_info = False,
|
||||
.malloc_replacement = False,
|
||||
.xml_output = False,
|
||||
@@ -303,6 +304,14 @@ void VG_(needs_print_stats) (
|
||||
VG_(tdict).tool_print_stats = print_stats;
|
||||
}
|
||||
|
||||
void VG_(needs_info_location) (
|
||||
void (*info_location)(Addr)
|
||||
)
|
||||
{
|
||||
VG_(needs).info_location = True;
|
||||
VG_(tdict).tool_info_location = info_location;
|
||||
}
|
||||
|
||||
void VG_(needs_malloc_replacement)(
|
||||
void* (*malloc) ( ThreadId, SizeT ),
|
||||
void* (*__builtin_new) ( ThreadId, SizeT ),
|
||||
|
||||
42
coregrind/pub_core_addrinfo.h
Normal file
42
coregrind/pub_core_addrinfo.h
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Obtaining information about an address. pub_core_addrinfo.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2014-2014 Philippe Waroquiers
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __PUB_CORE_ADDRINFO_H
|
||||
#define __PUB_CORE_ADDRINFO_H
|
||||
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
// No core-only exports; everything in this module is visible to both
|
||||
// the core and tools.
|
||||
|
||||
#endif // __PUB_CORE_ADDRINFO_H
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -127,6 +127,23 @@ extern void VG_(print_all_arena_stats) ( void );
|
||||
|
||||
extern void VG_(print_arena_cc_analysis) ( void );
|
||||
|
||||
typedef
|
||||
struct _AddrArenaInfo
|
||||
AddrArenaInfo;
|
||||
|
||||
struct _AddrArenaInfo {
|
||||
ArenaId aid;
|
||||
const HChar* name; // arena name, !NULL if Addr a points in an arena.
|
||||
SizeT block_szB;
|
||||
PtrdiffT rwoffset;
|
||||
Bool free; // True if this is in the arena free zone.
|
||||
};
|
||||
/* If Addr a points in one of the allocation arenas, describes Addr a in *aai
|
||||
otherwise sets *aai to 0/NULL/...
|
||||
Note that no information is produced for addresses allocated with
|
||||
VG_(arena_perm_malloc). */
|
||||
extern void VG_(describe_arena_addr) ( Addr a, /*OUT*/AddrArenaInfo* aai );
|
||||
|
||||
#endif // __PUB_CORE_MALLOCFREE_H
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@@ -89,6 +89,7 @@ typedef
|
||||
Bool syscall_wrapper;
|
||||
Bool sanity_checks;
|
||||
Bool print_stats;
|
||||
Bool info_location;
|
||||
Bool var_info;
|
||||
Bool malloc_replacement;
|
||||
Bool xml_output;
|
||||
@@ -153,6 +154,9 @@ typedef struct {
|
||||
// VG_(needs).print_stats
|
||||
void (*tool_print_stats)(void);
|
||||
|
||||
// VG_(needs).info_location
|
||||
void (*tool_info_location)(Addr a);
|
||||
|
||||
// VG_(needs).malloc_replacement
|
||||
void* (*tool_malloc) (ThreadId, SizeT);
|
||||
void* (*tool___builtin_new) (ThreadId, SizeT);
|
||||
|
||||
@@ -1267,6 +1267,7 @@ vgdb v.set log_output -c leak_check any
|
||||
<para>This section describes the Valgrind monitor commands, available
|
||||
regardless of the Valgrind tool selected. For the tool specific
|
||||
commands, refer to <xref linkend="mc-manual.monitor-commands"/>,
|
||||
<xref linkend="hg-manual.monitor-commands"/>,
|
||||
<xref linkend="cl-manual.monitor-commands"/> and
|
||||
<xref linkend="ms-manual.monitor-commands"/>. </para>
|
||||
|
||||
@@ -1295,6 +1296,32 @@ client request.
|
||||
found.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>v.info location <addr></varname> outputs
|
||||
information about the location <addr>. Possibly, the
|
||||
following are described: global variables, local (stack)
|
||||
variables, allocated or freed blocks, ... The information
|
||||
produced depends on the tool and on the options given to valgrind.
|
||||
Some tools (e.g. memcheck and helgrind) produce more detailed
|
||||
information for client heap blocks. For example, these tools show
|
||||
the stacktrace where the heap block was allocated. If a tool does
|
||||
not replace the malloc/free/... functions, then client heap blocks
|
||||
will not be described. Use the
|
||||
option <varname>--read-var-info=yes</varname> to obtain more
|
||||
detailed information about global or local (stack) variables.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor v.info location 0x8050b20
|
||||
Location 0x8050b20 is 0 bytes inside global var "mx"
|
||||
declared at tc19_shadowmem.c:19
|
||||
|
||||
(gdb) mo v.in loc 0x582f33c
|
||||
Location 0x582f33c is 0 bytes inside local var "info"
|
||||
declared at tc19_shadowmem.c:282, in frame #1 of thread 3
|
||||
(gdb)
|
||||
]]></programlisting>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>v.info n_errs_found [msg]</varname> shows the number of
|
||||
errors found so far, the nr of errors shown so far and the current
|
||||
|
||||
@@ -5,10 +5,15 @@ dist_noinst_SCRIPTS = \
|
||||
invoker simulate_control_c make_local_links \
|
||||
filter_gdb filter_make_empty \
|
||||
filter_memcheck_monitor filter_stderr filter_vgdb \
|
||||
send_signal
|
||||
filter_helgrind_monitor send_signal
|
||||
|
||||
EXTRA_DIST = \
|
||||
README_DEVELOPERS \
|
||||
hginfo.stderrB.exp \
|
||||
hginfo.stderr.exp \
|
||||
hginfo.stdinB.gdb \
|
||||
hginfo.stdoutB.exp \
|
||||
hginfo.vgtest \
|
||||
mcblocklistsearch.stderr.exp \
|
||||
mcblocklistsearch.stdinB.gdb \
|
||||
mcblocklistsearch.vgtest \
|
||||
|
||||
10
gdbserver_tests/filter_helgrind_monitor
Executable file
10
gdbserver_tests/filter_helgrind_monitor
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /bin/sh
|
||||
|
||||
# used to filter helgrind output shown by gdb/vgdb.
|
||||
|
||||
dir=`dirname $0`
|
||||
|
||||
$dir/../helgrind/tests/filter_stderr "$@" |
|
||||
|
||||
# filter vgdb messages
|
||||
$dir/filter_vgdb
|
||||
3
gdbserver_tests/hginfo.stderr.exp
Normal file
3
gdbserver_tests/hginfo.stderr.exp
Normal file
@@ -0,0 +1,3 @@
|
||||
(action at startup) vgdb me ...
|
||||
|
||||
|
||||
18
gdbserver_tests/hginfo.stderrB.exp
Normal file
18
gdbserver_tests/hginfo.stderrB.exp
Normal file
@@ -0,0 +1,18 @@
|
||||
relaying data between gdb and process ....
|
||||
vgdb-error value changed from 0 to 999999
|
||||
Lock ga 0x........ {
|
||||
Address 0x........ is 0 bytes inside data symbol "mx"
|
||||
kind mbRec
|
||||
{ W1:thread #x tid 2 }
|
||||
}
|
||||
Address 0x........ is 0 bytes inside a block of size 1,008 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: th (hg01_all_ok.c:22)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Lock ga 0x........ {
|
||||
Address 0x........ is 0 bytes inside data symbol "mx"
|
||||
kind mbRec
|
||||
{ W1:thread #x tid 3 }
|
||||
}
|
||||
Address 0x........ is 0 bytes inside an unallocated block of size 1,008 in arena "client"
|
||||
20
gdbserver_tests/hginfo.stdinB.gdb
Normal file
20
gdbserver_tests/hginfo.stdinB.gdb
Normal file
@@ -0,0 +1,20 @@
|
||||
# connect gdb to Valgrind gdbserver:
|
||||
target remote | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-hginfo
|
||||
echo vgdb launched process attached\n
|
||||
monitor v.set vgdb-error 999999
|
||||
#
|
||||
#
|
||||
# insert break:
|
||||
break breakme
|
||||
#
|
||||
# continue till each break and execute via gdb the monitor commands
|
||||
# ptr must be allocated at this state:
|
||||
continue
|
||||
monitor info locks
|
||||
eval "monitor v.info location %p", ptr
|
||||
# ptr must be freed at this state
|
||||
continue
|
||||
monitor info locks
|
||||
eval "monitor v.info location %p", ptr
|
||||
continue
|
||||
quit
|
||||
11
gdbserver_tests/hginfo.stdoutB.exp
Normal file
11
gdbserver_tests/hginfo.stdoutB.exp
Normal file
@@ -0,0 +1,11 @@
|
||||
Breakpoint 1 at 0x........: file hg01_all_ok.c, line 13.
|
||||
Continuing.
|
||||
[New Thread ....]
|
||||
Breakpoint 1, breakme () at hg01_all_ok.c:13
|
||||
13 if (shared == 1)
|
||||
Continuing.
|
||||
[New Thread ....]
|
||||
Breakpoint 1, breakme () at hg01_all_ok.c:13
|
||||
13 if (shared == 1)
|
||||
Continuing.
|
||||
Program exited normally.
|
||||
13
gdbserver_tests/hginfo.vgtest
Normal file
13
gdbserver_tests/hginfo.vgtest
Normal file
@@ -0,0 +1,13 @@
|
||||
# test helgrind monitor command
|
||||
# test 'v.info location' monitor command
|
||||
prog: ../helgrind/tests/hg01_all_ok
|
||||
vgopts: --tool=helgrind --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-hginfo -q
|
||||
prereq: test -e gdb.eval
|
||||
stdout_filter: filter_make_empty
|
||||
stderr_filter: filter_stderr
|
||||
progB: gdb
|
||||
argsB: --quiet -l 60 --nx ../helgrind/tests/hg01_all_ok
|
||||
stdinB: hginfo.stdinB.gdb
|
||||
stdoutB_filter: filter_gdb
|
||||
stderrB_filter: filter_helgrind_monitor
|
||||
stderrB_filter_args: hg01_all_ok.c
|
||||
@@ -3,6 +3,7 @@ general valgrind monitor commands:
|
||||
v.wait [<ms>] : sleep <ms> (default 0) then continue
|
||||
v.info all_errors : show all errors found so far
|
||||
v.info last_error : show last error found
|
||||
v.info location <addr> : show information about location <addr>
|
||||
v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
|
||||
v.info open_fds : show open file descriptors (only if --track-fds=yes)
|
||||
v.kill : kill the Valgrind process
|
||||
@@ -47,6 +48,7 @@ general valgrind monitor commands:
|
||||
v.wait [<ms>] : sleep <ms> (default 0) then continue
|
||||
v.info all_errors : show all errors found so far
|
||||
v.info last_error : show last error found
|
||||
v.info location <addr> : show information about location <addr>
|
||||
v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
|
||||
v.info open_fds : show open file descriptors (only if --track-fds=yes)
|
||||
v.kill : kill the Valgrind process
|
||||
|
||||
@@ -5,6 +5,7 @@ general valgrind monitor commands:
|
||||
v.wait [<ms>] : sleep <ms> (default 0) then continue
|
||||
v.info all_errors : show all errors found so far
|
||||
v.info last_error : show last error found
|
||||
v.info location <addr> : show information about location <addr>
|
||||
v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
|
||||
v.info open_fds : show open file descriptors (only if --track-fds=yes)
|
||||
v.kill : kill the Valgrind process
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# test the memcheck monitor help
|
||||
# test the massif help and massif snapshots.
|
||||
prereq: test -e gdb
|
||||
prog: t
|
||||
vgopts: --tool=massif --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mssnapshot
|
||||
|
||||
@@ -1291,8 +1291,8 @@ Lock ga 0x8049a20 {
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
Lock ga 0x8049a20 {
|
||||
Location 0x8049a20 is 0 bytes inside global var "s_rwlock"
|
||||
declared at rwlock_race.c:17
|
||||
Location 0x8049a20 is 0 bytes inside global var "s_rwlock"
|
||||
declared at rwlock_race.c:17
|
||||
kind rdwr
|
||||
{ R1:thread #3 tid 3 }
|
||||
}
|
||||
@@ -1300,27 +1300,6 @@ declared at rwlock_race.c:17
|
||||
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>describe <addr></varname> describes the address
|
||||
<addr>. For example, an heap address will be described by the
|
||||
length of the heap block and the stacktrace where this block was allocated.
|
||||
The option <varname>--read-var-info=yes</varname> allows to give information
|
||||
about global or local variables.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor describe 0x404e028
|
||||
|
||||
address 0x404E028 is 0 bytes inside a block of size 100 alloc'd
|
||||
==16448== at 0x4028AA5: malloc (vg_replace_malloc.c:292)
|
||||
==16448== by 0x8048BD7: main (tc19_shadowmem.c:144)
|
||||
(gdb) mo d 0xbec6f040
|
||||
|
||||
Location 0xbec6f040 is 0 bytes inside info.child,
|
||||
declared at tc19_shadowmem.c:139, in frame #0 of thread 1
|
||||
(gdb)
|
||||
]]></programlisting>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -36,19 +36,19 @@
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_debuginfo.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_addrdescr.h" /* self */
|
||||
|
||||
void HG_(init_AddrDescr) ( AddrDescr* ad ) {
|
||||
VG_(memset)(ad, 0, sizeof(*ad) );
|
||||
}
|
||||
|
||||
void HG_(describe_addr) ( Addr a, /*OUT*/AddrDescr* ad )
|
||||
void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
|
||||
{
|
||||
tl_assert(!ad->hctxt);
|
||||
tl_assert(!ad->descr1);
|
||||
tl_assert(!ad->descr2);
|
||||
tl_assert(ai->tag == Addr_Undescribed);
|
||||
|
||||
/* hctxt/haddr/hszB describe the addr if it is a heap block. */
|
||||
ExeContext* hctxt;
|
||||
Addr haddr;
|
||||
SizeT hszB;
|
||||
|
||||
/* First, see if it's in any heap block. Unfortunately this
|
||||
means a linear search through all allocated heap blocks. The
|
||||
@@ -57,135 +57,42 @@ void HG_(describe_addr) ( Addr a, /*OUT*/AddrDescr* ad )
|
||||
should have an allocation context. */
|
||||
Bool is_heapblock
|
||||
= HG_(mm_find_containing_block)(
|
||||
&ad->hctxt,
|
||||
&ad->haddr,
|
||||
&ad->hszB,
|
||||
&hctxt,
|
||||
&haddr,
|
||||
&hszB,
|
||||
a
|
||||
);
|
||||
tl_assert(is_heapblock == (ad->hctxt != NULL));
|
||||
|
||||
if (!ad->hctxt) {
|
||||
/* It's not in any heap block. See if we can map it to a
|
||||
stack or global symbol. */
|
||||
|
||||
ad->descr1
|
||||
= VG_(newXA)( HG_(zalloc), "hg.addrdescr.descr1",
|
||||
HG_(free), sizeof(HChar) );
|
||||
ad->descr2
|
||||
= VG_(newXA)( HG_(zalloc), "hg.addrdescr.descr2",
|
||||
HG_(free), sizeof(HChar) );
|
||||
|
||||
(void) VG_(get_data_description)( ad->descr1,
|
||||
ad->descr2,
|
||||
a );
|
||||
|
||||
/* 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)(ad->descr1, 0 ))) {
|
||||
VG_(deleteXA)( ad->descr1 );
|
||||
ad->descr1 = NULL;
|
||||
}
|
||||
if (0 == VG_(strlen)( VG_(indexXA)( ad->descr2, 0 ))) {
|
||||
VG_(deleteXA)( ad->descr2 );
|
||||
ad->descr2 = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HG_(pp_addrdescr) (Bool xml, const HChar* what, Addr addr,
|
||||
AddrDescr* ad,
|
||||
void(*print)(const HChar *format, ...))
|
||||
{
|
||||
/* If we have a description of the address in terms of a heap
|
||||
block, show it. */
|
||||
if (ad->hctxt) {
|
||||
SizeT delta = addr - ad->haddr;
|
||||
if (xml) {
|
||||
(*print)(" <auxwhat>%s %p is %ld bytes inside a block "
|
||||
"of size %ld alloc'd</auxwhat>\n", what,
|
||||
(void*)addr, delta,
|
||||
ad->hszB);
|
||||
VG_(pp_ExeContext)( ad->hctxt );
|
||||
} else {
|
||||
(*print)("\n");
|
||||
(*print)("%s %p is %ld bytes inside a block "
|
||||
"of size %ld alloc'd\n", what,
|
||||
(void*)addr, delta,
|
||||
ad->hszB);
|
||||
VG_(pp_ExeContext)( ad->hctxt );
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (ad->descr1)
|
||||
(*print)( " %s\n",
|
||||
(HChar*)VG_(indexXA)( ad->descr1, 0 ) );
|
||||
if (ad->descr2)
|
||||
(*print)( " %s\n",
|
||||
(HChar*)VG_(indexXA)( ad->descr2, 0 ) );
|
||||
if (is_heapblock) {
|
||||
tl_assert(is_heapblock == (hctxt != NULL));
|
||||
ai->tag = Addr_Block;
|
||||
ai->Addr.Block.block_kind = Block_Mallocd;
|
||||
ai->Addr.Block.block_desc = "block";
|
||||
ai->Addr.Block.block_szB = hszB;
|
||||
ai->Addr.Block.rwoffset = (Word)(a) - (Word)(haddr);
|
||||
ai->Addr.Block.allocated_at = hctxt;
|
||||
ai->Addr.Block.freed_at = VG_(null_ExeContext)();;
|
||||
} else {
|
||||
if (ad->descr1 || ad->descr2)
|
||||
(*print)("\n");
|
||||
if (ad->descr1)
|
||||
(*print)( "%s\n",
|
||||
(HChar*)VG_(indexXA)( ad->descr1, 0 ) );
|
||||
if (ad->descr2)
|
||||
(*print)( "%s\n",
|
||||
(HChar*)VG_(indexXA)( ad->descr2, 0 ) );
|
||||
/* No block found. Search a non-heap block description. */
|
||||
VG_(describe_addr) (a, ai);
|
||||
}
|
||||
}
|
||||
|
||||
static void void_printf(const HChar *format, ...)
|
||||
{
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
VG_(vprintf)(format, vargs);
|
||||
va_end(vargs);
|
||||
}
|
||||
|
||||
Bool HG_(get_and_pp_addrdescr) (const HChar* what, Addr addr)
|
||||
Bool HG_(get_and_pp_addrdescr) (Addr addr)
|
||||
{
|
||||
|
||||
Bool ret;
|
||||
AddrDescr glad;
|
||||
AddrInfo glai;
|
||||
|
||||
HG_(init_AddrDescr) (&glad);
|
||||
glai.tag = Addr_Undescribed;
|
||||
HG_(describe_addr) (addr, &glai);
|
||||
VG_(pp_addrinfo) (addr, &glai);
|
||||
ret = glai.tag != Addr_Unknown;
|
||||
|
||||
HG_(describe_addr) (addr, &glad);
|
||||
|
||||
HG_(pp_addrdescr) (False /* xml */, what, addr,
|
||||
&glad,
|
||||
void_printf);
|
||||
ret = glad.hctxt || glad.descr1 || glad.descr2;
|
||||
|
||||
HG_(clear_addrdesc) (&glad);
|
||||
VG_(clear_addrinfo) (&glai);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HG_(clear_addrdesc) ( AddrDescr* ad)
|
||||
{
|
||||
ad->hctxt = NULL;
|
||||
ad->haddr = 0;
|
||||
ad->hszB = 0;
|
||||
if (ad->descr1 != NULL) {
|
||||
VG_(deleteXA)( ad->descr1 );
|
||||
ad->descr1 = NULL;
|
||||
}
|
||||
if (ad->descr2 != NULL) {
|
||||
VG_(deleteXA)( ad->descr2 );
|
||||
ad->descr2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_addrdescr.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@@ -33,45 +33,22 @@
|
||||
#ifndef __HG_ADDRDESCR_H
|
||||
#define __HG_ADDRDESCR_H
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Address Description ---*/
|
||||
/*--- Used e.g. to describe an address in a Race cond. error ---*/
|
||||
/*--- or a lock. ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
typedef
|
||||
struct {
|
||||
/* descr1/2 provide a description of stack/global locs */
|
||||
XArray* descr1; /* XArray* of HChar */
|
||||
XArray* descr2; /* XArray* of HChar */
|
||||
/* hctxt/haddr/hszB describe the addr if it is a heap block. */
|
||||
ExeContext* hctxt;
|
||||
Addr haddr;
|
||||
SizeT hszB;
|
||||
}
|
||||
AddrDescr;
|
||||
|
||||
/* Initialises an empty AddrDescr. */
|
||||
void HG_(init_AddrDescr) ( AddrDescr* ad );
|
||||
|
||||
/* Describe an address as best you can, for error messages or
|
||||
lock description, putting the result in ad.
|
||||
This allocates some memory in ad, to be cleared with VG_(clear_addrdesc). */
|
||||
extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrDescr* ad );
|
||||
lock description, putting the result in ai.
|
||||
This might allocate some memory in ai, to be cleared with
|
||||
VG_(clear_addrinfo). */
|
||||
extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai );
|
||||
|
||||
/* Prints (using *print) the readable description of addr given in ad.
|
||||
/* Prints (using *print) the readable description of addr given in ai.
|
||||
"what" identifies the type pointed to by addr (e.g. a lock). */
|
||||
extern void HG_(pp_addrdescr) (Bool xml, const HChar* what, Addr addr,
|
||||
AddrDescr* ad,
|
||||
AddrInfo* ai,
|
||||
void(*print)(const HChar *format, ...));
|
||||
|
||||
/* Get a readable description of addr, then print it using HG_(pp_addrdescr)
|
||||
using xml False and VG_(printf) to emit the characters.
|
||||
Returns True if a description was found/printed, False otherwise. */
|
||||
extern Bool HG_(get_and_pp_addrdescr) (const HChar* what, Addr a);
|
||||
|
||||
/* Free all memory allocated by HG_(describe_addr)
|
||||
Sets all elements of ad to 0/NULL. */
|
||||
extern void HG_(clear_addrdesc) ( AddrDescr* ad);
|
||||
extern Bool HG_(get_and_pp_addrdescr) (Addr a);
|
||||
|
||||
/* For error creation/address description:
|
||||
map 'data_addr' to a malloc'd chunk, if any.
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "pub_tool_debuginfo.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_options.h" // VG_(clo_xml)
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_addrdescr.h"
|
||||
@@ -292,7 +293,7 @@ typedef
|
||||
struct {
|
||||
Addr data_addr;
|
||||
Int szB;
|
||||
AddrDescr data_addrdescr;
|
||||
AddrInfo data_addrinfo;
|
||||
Bool isWrite;
|
||||
Thread* thr;
|
||||
Lock** locksHeldW;
|
||||
@@ -406,7 +407,7 @@ UInt HG_(update_extra) ( Error* err )
|
||||
VG_(printf)("HG_(update_extra): "
|
||||
"%d conflicting-event queries\n", xxx);
|
||||
|
||||
HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrdescr);
|
||||
HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo);
|
||||
|
||||
/* And poke around in the conflicting-event map, to see if we
|
||||
can rustle up a plausible-looking conflicting memory access
|
||||
@@ -488,7 +489,7 @@ void HG_(record_error_Race) ( Thread* thr,
|
||||
/* Skip on the detailed description of the raced-on address at this
|
||||
point; it's expensive. Leave it for the update_extra function
|
||||
if we ever make it that far. */
|
||||
HG_(init_AddrDescr) (&xe.XE.Race.data_addrdescr);
|
||||
xe.XE.Race.data_addrinfo.tag = Addr_Undescribed;
|
||||
// FIXME: tid vs thr
|
||||
// Skip on any of the conflicting-access info at this point.
|
||||
// It's expensive to obtain, and this error is more likely than
|
||||
@@ -1232,10 +1233,7 @@ void HG_(pp_Error) ( Error* err )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HG_(pp_addrdescr) (xml, "Address", err_ga,
|
||||
&xe->XE.Race.data_addrdescr,
|
||||
emit);
|
||||
VG_(pp_addrinfo) (err_ga, &xe->XE.Race.data_addrinfo);
|
||||
break; /* case XE_Race */
|
||||
} /* case XE_Race */
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "pub_tool_libcproc.h" // VG_(atfork)
|
||||
#include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
|
||||
#include "pub_tool_poolalloc.h"
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_wordset.h"
|
||||
@@ -470,11 +471,11 @@ static void pp_Lock ( Int d, Lock* lk,
|
||||
{
|
||||
space(d+0);
|
||||
if (show_internal_data)
|
||||
VG_(printf)("Lock %p (ga %#lx) {", lk, lk->guestaddr);
|
||||
VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
|
||||
else
|
||||
VG_(printf)("Lock ga %#lx {", lk->guestaddr);
|
||||
VG_(printf)("Lock ga %#lx {\n", lk->guestaddr);
|
||||
if (!show_lock_addrdescr
|
||||
|| !HG_(get_and_pp_addrdescr) ("lock", (Addr) lk->guestaddr))
|
||||
|| !HG_(get_and_pp_addrdescr) ((Addr) lk->guestaddr))
|
||||
VG_(printf)("\n");
|
||||
|
||||
if (sHOW_ADMIN) {
|
||||
@@ -4745,7 +4746,6 @@ static void print_monitor_help ( void )
|
||||
(
|
||||
"\n"
|
||||
"helgrind monitor commands:\n"
|
||||
" describe <addr> : outputs a description of <addr>\n"
|
||||
" info locks : show list of locks and their status\n"
|
||||
"\n");
|
||||
}
|
||||
@@ -4765,7 +4765,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
starts with the same first letter(s) as an already existing
|
||||
command. This ensures a shorter abbreviation for the user. */
|
||||
switch (VG_(keyword_id)
|
||||
("help info describe",
|
||||
("help info",
|
||||
wcmd, kwd_report_duplicated_matches)) {
|
||||
case -2: /* multiple matches */
|
||||
return True;
|
||||
@@ -4799,16 +4799,6 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
tl_assert(0);
|
||||
}
|
||||
return True;
|
||||
case 2: { /* describe */
|
||||
Addr address;
|
||||
SizeT szB = 1;
|
||||
VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
|
||||
if (address == (Addr) 0 && szB == 0) return True;
|
||||
if (!HG_(get_and_pp_addrdescr) ("address", address))
|
||||
VG_(gdb_printf) ("No description found for address %p\n",
|
||||
(void*)address);
|
||||
return True;
|
||||
}
|
||||
default:
|
||||
tl_assert(0);
|
||||
return False;
|
||||
@@ -5391,6 +5381,11 @@ static void hg_post_clo_init ( void )
|
||||
initialise_data_structures(hbthr_root);
|
||||
}
|
||||
|
||||
static void hg_info_location (Addr a)
|
||||
{
|
||||
(void) HG_(get_and_pp_addrdescr) (a);
|
||||
}
|
||||
|
||||
static void hg_pre_clo_init ( void )
|
||||
{
|
||||
VG_(details_name) ("Helgrind");
|
||||
@@ -5431,6 +5426,7 @@ static void hg_pre_clo_init ( void )
|
||||
// hg_expensive_sanity_check);
|
||||
|
||||
VG_(needs_print_stats) (hg_print_stats);
|
||||
VG_(needs_info_location) (hg_info_location);
|
||||
|
||||
VG_(needs_malloc_replacement) (hg_cli__malloc,
|
||||
hg_cli____builtin_new,
|
||||
|
||||
@@ -29,6 +29,7 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:147)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -45,6 +46,7 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:144)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -61,6 +63,7 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -77,6 +80,7 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -93,6 +97,7 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -113,5 +118,6 @@ Locks held: none
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
Finished.
|
||||
|
||||
@@ -24,6 +24,7 @@ Locks held: none
|
||||
This conflicts with a previous read of size 1 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: main (free_is_write.c:36)
|
||||
Address 0x........ is 5 bytes inside an unallocated block of size 16 in arena "client"
|
||||
|
||||
Done.
|
||||
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
/* All OK */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int shared;
|
||||
static int shared = 0;
|
||||
static char *ptr;
|
||||
|
||||
static void breakme(void)
|
||||
{
|
||||
if (shared == 1)
|
||||
memset (ptr, 0x55, 1000);
|
||||
}
|
||||
|
||||
static void *th(void *v)
|
||||
{
|
||||
pthread_mutex_lock(&mx);
|
||||
shared++;
|
||||
if (shared == 1) {
|
||||
ptr = malloc (1008);
|
||||
breakme();
|
||||
}
|
||||
if (shared == 2) {
|
||||
free (ptr);
|
||||
breakme();
|
||||
}
|
||||
pthread_mutex_unlock(&mx);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -22,9 +22,8 @@ Locks held: none
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: main (hg03_inherit.c:60)
|
||||
|
||||
Location 0x........ is 0 bytes inside shared[1],
|
||||
a global variable declared at hg03_inherit.c:11
|
||||
Location 0x........ is 0 bytes inside shared[1],
|
||||
a global variable declared at hg03_inherit.c:11
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -28,9 +28,8 @@ Locks held: none
|
||||
at 0x........: th (hg04_race.c:10)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "shared"
|
||||
declared at hg04_race.c:6
|
||||
Location 0x........ is 0 bytes inside global var "shared"
|
||||
declared at hg04_race.c:6
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -45,9 +44,8 @@ Locks held: none
|
||||
at 0x........: th (hg04_race.c:10)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "shared"
|
||||
declared at hg04_race.c:6
|
||||
Location 0x........ is 0 bytes inside global var "shared"
|
||||
declared at hg04_race.c:6
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -28,9 +28,8 @@ Locks held: none
|
||||
at 0x........: th (hg05_race2.c:17)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside foo.poot[5].plop[11],
|
||||
declared at hg05_race2.c:24, in frame #x of thread x
|
||||
Location 0x........ is 0 bytes inside foo.poot[5].plop[11],
|
||||
declared at hg05_race2.c:24, in frame #x of thread x
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -45,9 +44,8 @@ Locks held: none
|
||||
at 0x........: th (hg05_race2.c:17)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside foo.poot[5].plop[11],
|
||||
declared at hg05_race2.c:24, in frame #x of thread x
|
||||
Location 0x........ is 0 bytes inside foo.poot[5].plop[11],
|
||||
declared at hg05_race2.c:24, in frame #x of thread x
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -33,4 +33,5 @@ Locks held: 1, at address 0x........
|
||||
at 0x........: child_fn (locked_vs_unlocked1.c:19)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 0 bytes inside data symbol "x"
|
||||
|
||||
|
||||
@@ -33,4 +33,5 @@ Locks held: none
|
||||
at 0x........: child_fn (locked_vs_unlocked1.c:19)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 0 bytes inside data symbol "x"
|
||||
|
||||
|
||||
@@ -39,4 +39,5 @@ Locks held: 2, at address 0x........ (and 1 that can't be shown)
|
||||
at 0x........: child_fn1 (locked_vs_unlocked2.c:29)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 0 bytes inside data symbol "x"
|
||||
|
||||
|
||||
@@ -31,4 +31,5 @@ Locks held: 1, at address 0x........
|
||||
at 0x........: child_fn1 (locked_vs_unlocked3.c:28)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 0 bytes inside data symbol "x"
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 0 bytes inside a block of size 1 alloc'd
|
||||
Address 0x........ is 0 bytes inside a block of size 1 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
|
||||
@@ -29,8 +29,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 0 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 0 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -48,8 +47,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 1 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 1 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -67,8 +65,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 2 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 2 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -86,8 +83,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 3 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 3 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -105,8 +101,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 4 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 4 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -124,8 +119,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 5 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 5 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -143,8 +137,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 6 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 6 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -162,8 +155,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 7 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 7 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -181,8 +173,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 8 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 8 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -200,8 +191,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 9 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 9 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -219,8 +209,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 10 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 10 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -238,8 +227,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 11 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 11 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -257,8 +245,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 12 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 12 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -276,8 +263,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 13 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 13 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -295,8 +281,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 14 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 14 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -314,8 +299,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 15 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 15 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -333,8 +317,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 16 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 16 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -352,8 +335,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 17 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 17 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -371,8 +353,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 18 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 18 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -390,8 +371,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 19 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 19 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -409,8 +389,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 20 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 20 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -428,8 +407,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 21 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 21 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -447,8 +425,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 22 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 22 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -466,8 +443,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 23 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 23 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -485,8 +461,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 24 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 24 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -504,8 +479,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 25 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 25 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -523,8 +497,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 26 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 26 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -542,8 +515,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 27 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 27 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -561,8 +533,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 28 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 28 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -580,8 +551,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 29 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 29 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -599,8 +569,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 30 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 30 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
@@ -618,8 +587,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 31 bytes inside a block of size 32 alloc'd
|
||||
Address 0x........ is 31 bytes inside a block of size 32 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
|
||||
@@ -29,8 +29,7 @@ Locks held: none
|
||||
at 0x........: threadfunc (pth_barrier.c:60)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Address 0x........ is 0 bytes inside a block of size 1 alloc'd
|
||||
Address 0x........ is 0 bytes inside a block of size 1 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: barriers_and_races (pth_barrier.c:76)
|
||||
by 0x........: main (pth_barrier.c:122)
|
||||
|
||||
@@ -28,6 +28,7 @@ Locks held: none
|
||||
by 0x........: thread_func (pth_cond_destroy_busy.c:31)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_cond"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -28,9 +28,8 @@ Locks held: none
|
||||
at 0x........: thread_func (rwlock_race.c:29)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "s_racy"
|
||||
declared at rwlock_race.c:18
|
||||
Location 0x........ is 0 bytes inside global var "s_racy"
|
||||
declared at rwlock_race.c:18
|
||||
|
||||
Result: 2
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc01_simple_race.c:14)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "x"
|
||||
declared at tc01_simple_race.c:9
|
||||
Location 0x........ is 0 bytes inside global var "x"
|
||||
declared at tc01_simple_race.c:9
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -37,9 +36,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc01_simple_race.c:14)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "x"
|
||||
declared at tc01_simple_race.c:9
|
||||
Location 0x........ is 0 bytes inside global var "x"
|
||||
declared at tc01_simple_race.c:9
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -22,9 +22,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc05_simple_race.c:19)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "y"
|
||||
declared at tc05_simple_race.c:10
|
||||
Location 0x........ is 0 bytes inside global var "y"
|
||||
declared at tc05_simple_race.c:10
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -37,9 +36,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc05_simple_race.c:19)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "y"
|
||||
declared at tc05_simple_race.c:10
|
||||
Location 0x........ is 0 bytes inside global var "y"
|
||||
declared at tc05_simple_race.c:10
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -22,9 +22,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc06_two_races.c:14)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprot1"
|
||||
declared at tc06_two_races.c:9
|
||||
Location 0x........ is 0 bytes inside global var "unprot1"
|
||||
declared at tc06_two_races.c:9
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -37,9 +36,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc06_two_races.c:14)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprot1"
|
||||
declared at tc06_two_races.c:9
|
||||
Location 0x........ is 0 bytes inside global var "unprot1"
|
||||
declared at tc06_two_races.c:9
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -52,9 +50,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc06_two_races.c:18)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprot2"
|
||||
declared at tc06_two_races.c:9
|
||||
Location 0x........ is 0 bytes inside global var "unprot2"
|
||||
declared at tc06_two_races.c:9
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -67,9 +64,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc06_two_races.c:18)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprot2"
|
||||
declared at tc06_two_races.c:9
|
||||
Location 0x........ is 0 bytes inside global var "unprot2"
|
||||
declared at tc06_two_races.c:9
|
||||
|
||||
|
||||
ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -22,9 +22,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc16_byterace.c:13)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside bytes[4],
|
||||
a global variable declared at tc16_byterace.c:7
|
||||
Location 0x........ is 0 bytes inside bytes[4],
|
||||
a global variable declared at tc16_byterace.c:7
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -37,9 +36,8 @@ Locks held: none
|
||||
at 0x........: child_fn (tc16_byterace.c:13)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside bytes[4],
|
||||
a global variable declared at tc16_byterace.c:7
|
||||
Location 0x........ is 0 bytes inside bytes[4],
|
||||
a global variable declared at tc16_byterace.c:7
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,9 +28,8 @@ Locks held: none
|
||||
at 0x........: racy_child (tc20_verifywrap.c:34)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprotected"
|
||||
declared at tc20_verifywrap.c:27
|
||||
Location 0x........ is 0 bytes inside global var "unprotected"
|
||||
declared at tc20_verifywrap.c:27
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -28,9 +28,8 @@ Locks held: none
|
||||
at 0x........: child (tc21_pthonce.c:74)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprotected2"
|
||||
declared at tc21_pthonce.c:51
|
||||
Location 0x........ is 0 bytes inside global var "unprotected2"
|
||||
declared at tc21_pthonce.c:51
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -45,9 +44,8 @@ Locks held: none
|
||||
at 0x........: child (tc21_pthonce.c:74)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Location 0x........ is 0 bytes inside global var "unprotected2"
|
||||
declared at tc21_pthonce.c:51
|
||||
Location 0x........ is 0 bytes inside global var "unprotected2"
|
||||
declared at tc21_pthonce.c:51
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
nobase_pkginclude_HEADERS = \
|
||||
pub_tool_basics.h \
|
||||
pub_tool_basics_asm.h \
|
||||
pub_tool_addrinfo.h \
|
||||
pub_tool_aspacehl.h \
|
||||
pub_tool_aspacemgr.h \
|
||||
pub_tool_clientstate.h \
|
||||
|
||||
153
include/pub_tool_addrinfo.h
Normal file
153
include/pub_tool_addrinfo.h
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Obtaining information about an address. pub_tool_addrinfo.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2000-2013 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __PUB_TOOL_ADDRINFO_H
|
||||
#define __PUB_TOOL_ADDRINFO_H
|
||||
|
||||
#include "pub_tool_basics.h" // VG_ macro
|
||||
|
||||
/*====================================================================*/
|
||||
/*=== Obtaining information about an address ===*/
|
||||
/*====================================================================*/
|
||||
|
||||
// Different kinds of blocks.
|
||||
// Block_Mallocd is used by tools that maintain detailed information about
|
||||
// Client allocated heap blocks.
|
||||
// Block_Freed is used by tools such as memcheck that maintain a 'quarantine'
|
||||
// list of blocks freed by the Client but not yet physically freed.
|
||||
// Block_MempoolChunk and Block_UserG are used for mempool or user defined heap
|
||||
// blocks.
|
||||
// Block_ClientArenaMallocd and Block_ClientArenaFree are used when the tool
|
||||
// replaces the malloc/free/... functions but does not maintain detailed
|
||||
// information about Client allocated heap blocks.
|
||||
// Block_ValgrindArenaMallocd and Block_ValgrindArenaFree are used for heap blocks
|
||||
// of Valgrind internal heap.
|
||||
typedef enum {
|
||||
Block_Mallocd = 111,
|
||||
Block_Freed,
|
||||
Block_MempoolChunk,
|
||||
Block_UserG,
|
||||
Block_ClientArenaMallocd,
|
||||
Block_ClientArenaFree,
|
||||
Block_ValgrindArenaMallocd,
|
||||
Block_ValgrindArenaFree,
|
||||
} BlockKind;
|
||||
|
||||
/* ------------------ Addresses -------------------- */
|
||||
|
||||
/* The classification of a faulting address. */
|
||||
typedef
|
||||
enum {
|
||||
Addr_Undescribed, // as-yet unclassified
|
||||
Addr_Unknown, // classification yielded nothing useful
|
||||
Addr_Block, // in malloc'd/free'd block
|
||||
Addr_Stack, // on a thread's stack
|
||||
Addr_DataSym, // in a global data sym
|
||||
Addr_Variable, // variable described by the debug info
|
||||
Addr_SectKind // last-ditch classification attempt
|
||||
}
|
||||
AddrTag;
|
||||
|
||||
typedef
|
||||
struct _AddrInfo
|
||||
AddrInfo;
|
||||
|
||||
struct _AddrInfo {
|
||||
AddrTag tag;
|
||||
union {
|
||||
// As-yet unclassified.
|
||||
struct { } Undescribed;
|
||||
|
||||
// On a stack.
|
||||
struct {
|
||||
ThreadId tid; // Which thread's stack?
|
||||
} Stack;
|
||||
|
||||
// This covers heap blocks (normal and from mempools), user-defined blocks,
|
||||
// and Arena blocks.
|
||||
struct {
|
||||
BlockKind block_kind;
|
||||
const HChar* block_desc; // "block", "mempool" or user-defined or arena
|
||||
SizeT block_szB;
|
||||
PtrdiffT rwoffset;
|
||||
ExeContext* allocated_at; // might be null_ExeContext.
|
||||
ExeContext* freed_at; // might be null_ExeContext.
|
||||
} Block;
|
||||
|
||||
// In a global .data symbol. This holds the first 127 chars of
|
||||
// the variable's name (zero terminated), plus a (memory) offset.
|
||||
struct {
|
||||
HChar name[128];
|
||||
PtrdiffT offset;
|
||||
} DataSym;
|
||||
|
||||
// Is described by Dwarf debug info. XArray*s of HChar.
|
||||
struct {
|
||||
XArray* /* of HChar */ descr1;
|
||||
XArray* /* of HChar */ descr2;
|
||||
} Variable;
|
||||
|
||||
// Could only narrow it down to be the PLT/GOT/etc of a given
|
||||
// object. Better than nothing, perhaps.
|
||||
struct {
|
||||
HChar objname[128];
|
||||
VgSectKind kind;
|
||||
} SectKind;
|
||||
|
||||
// Classification yielded nothing useful.
|
||||
struct { } Unknown;
|
||||
|
||||
} Addr;
|
||||
};
|
||||
|
||||
|
||||
/* Describe an address as best you can, putting the result in ai.
|
||||
On entry, ai->tag must be equal to Addr_Undescribed.
|
||||
This might allocate some memory, that can be cleared with
|
||||
VG_(clear_addrinfo). */
|
||||
extern void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai );
|
||||
|
||||
extern void VG_(clear_addrinfo) ( AddrInfo* ai);
|
||||
|
||||
/* Prints the AddrInfo ai describing a. */
|
||||
extern void VG_(pp_addrinfo) ( Addr a, AddrInfo* ai );
|
||||
|
||||
/* Same as VG_(pp_addrinfo) but provides some memcheck specific behaviour:
|
||||
* maybe_gcc indicates Addr a was just below the stack ptr when the error
|
||||
with a was encountered.
|
||||
* the message for Unknown tag is slightly different, as memcheck
|
||||
has a recently freed list. */
|
||||
extern void VG_(pp_addrinfo_mc) ( Addr a, AddrInfo* ai, Bool maybe_gcc );
|
||||
|
||||
#endif // __PUB_TOOL_ADDRINFO_H
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -180,9 +180,13 @@ extern Int VG_(keyword_id) (const HChar* keywords, const HChar* input_word,
|
||||
/* Extract an address and (optionally) a size from the string
|
||||
currently being parsed by strtok_r (see pub_tool_libcbase.h).
|
||||
If no size in the string, keeps the current value of szB.
|
||||
Returns address 0 and szB 0 if there is an error. Reports to the
|
||||
user problems via VG_(gdb_printf). */
|
||||
extern void VG_(strtok_get_address_and_size) (Addr* address,
|
||||
If parsing is ok,
|
||||
returns True.
|
||||
If parsing is not ok;
|
||||
set *address and *szB to 0,
|
||||
reports problem to the user using VG_(gdb_printf)
|
||||
returns False. */
|
||||
extern Bool VG_(strtok_get_address_and_size) (Addr* address,
|
||||
SizeT* szB,
|
||||
HChar **ssaveptr);
|
||||
|
||||
|
||||
@@ -106,6 +106,12 @@ extern UInt VG_(printf_xml) ( const HChar *format, ... )
|
||||
extern UInt VG_(vprintf_xml) ( const HChar *format, va_list vargs )
|
||||
PRINTF_CHECK(1, 0);
|
||||
|
||||
/* Do a printf-style operation on either the XML
|
||||
or normal output channel
|
||||
or gdb output channel, depending on the setting of VG_(clo_xml)
|
||||
and the state of VG_(log_output_sink). */
|
||||
extern UInt VG_(emit) ( const HChar* format, ... ) PRINTF_CHECK(1, 2);
|
||||
|
||||
/* Yet another, totally general, version of vprintf, which hands all
|
||||
output bytes to CHAR_SINK, passing it OPAQUE as the second arg. */
|
||||
extern void VG_(vcbprintf)( void(*char_sink)(HChar, void* opaque),
|
||||
|
||||
@@ -458,6 +458,13 @@ extern void VG_(needs_print_stats) (
|
||||
void (*print_stats)(void)
|
||||
);
|
||||
|
||||
/* Has the tool a tool specific function to retrieve and print location info
|
||||
of an address ? */
|
||||
extern void VG_(needs_info_location) (
|
||||
// Get and pp information about Addr
|
||||
void (*info_location)(Addr)
|
||||
);
|
||||
|
||||
/* Do we need to see variable type and location information? */
|
||||
extern void VG_(needs_var_info) ( void );
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_debuginfo.h" // VG_(get_dataname_and_offset)
|
||||
#include "pub_tool_xarray.h"
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
#include "mc_include.h"
|
||||
|
||||
@@ -56,81 +57,6 @@
|
||||
Bool MC_(any_value_errors) = False;
|
||||
|
||||
|
||||
// Different kinds of blocks.
|
||||
typedef enum {
|
||||
Block_Mallocd = 111,
|
||||
Block_Freed,
|
||||
Block_MempoolChunk,
|
||||
Block_UserG
|
||||
} BlockKind;
|
||||
|
||||
/* ------------------ Addresses -------------------- */
|
||||
|
||||
/* The classification of a faulting address. */
|
||||
typedef
|
||||
enum {
|
||||
Addr_Undescribed, // as-yet unclassified
|
||||
Addr_Unknown, // classification yielded nothing useful
|
||||
Addr_Block, // in malloc'd/free'd block
|
||||
Addr_Stack, // on a thread's stack
|
||||
Addr_DataSym, // in a global data sym
|
||||
Addr_Variable, // variable described by the debug info
|
||||
Addr_SectKind // last-ditch classification attempt
|
||||
}
|
||||
AddrTag;
|
||||
|
||||
typedef
|
||||
struct _AddrInfo
|
||||
AddrInfo;
|
||||
|
||||
struct _AddrInfo {
|
||||
AddrTag tag;
|
||||
union {
|
||||
// As-yet unclassified.
|
||||
struct { } Undescribed;
|
||||
|
||||
// On a stack.
|
||||
struct {
|
||||
ThreadId tid; // Which thread's stack?
|
||||
} Stack;
|
||||
|
||||
// This covers heap blocks (normal and from mempools) and user-defined
|
||||
// blocks.
|
||||
struct {
|
||||
BlockKind block_kind;
|
||||
const HChar* block_desc; // "block", "mempool" or user-defined
|
||||
SizeT block_szB;
|
||||
PtrdiffT rwoffset;
|
||||
ExeContext* allocated_at; // might be null_ExeContext.
|
||||
ExeContext* freed_at; // might be null_ExeContext.
|
||||
} Block;
|
||||
|
||||
// In a global .data symbol. This holds the first 127 chars of
|
||||
// the variable's name (zero terminated), plus a (memory) offset.
|
||||
struct {
|
||||
HChar name[128];
|
||||
PtrdiffT offset;
|
||||
} DataSym;
|
||||
|
||||
// Is described by Dwarf debug info. XArray*s of HChar.
|
||||
struct {
|
||||
XArray* /* of HChar */ descr1;
|
||||
XArray* /* of HChar */ descr2;
|
||||
} Variable;
|
||||
|
||||
// Could only narrow it down to be the PLT/GOT/etc of a given
|
||||
// object. Better than nothing, perhaps.
|
||||
struct {
|
||||
HChar objname[128];
|
||||
VgSectKind kind;
|
||||
} SectKind;
|
||||
|
||||
// Classification yielded nothing useful.
|
||||
struct { } Unknown;
|
||||
|
||||
} Addr;
|
||||
};
|
||||
|
||||
/* ------------------ Errors ----------------------- */
|
||||
|
||||
/* What kind of error it is. */
|
||||
@@ -288,119 +214,6 @@ static void emit ( const HChar* format, ... )
|
||||
}
|
||||
|
||||
|
||||
static void mc_pp_AddrInfo ( Addr a, AddrInfo* ai, Bool maybe_gcc )
|
||||
{
|
||||
const HChar* xpre = VG_(clo_xml) ? " <auxwhat>" : " ";
|
||||
const HChar* xpost = VG_(clo_xml) ? "</auxwhat>" : "";
|
||||
|
||||
switch (ai->tag) {
|
||||
case Addr_Unknown:
|
||||
if (maybe_gcc) {
|
||||
emit( "%sAddress 0x%llx is just below the stack ptr. "
|
||||
"To suppress, use: --workaround-gcc296-bugs=yes%s\n",
|
||||
xpre, (ULong)a, xpost );
|
||||
} else {
|
||||
emit( "%sAddress 0x%llx "
|
||||
"is not stack'd, malloc'd or (recently) free'd%s\n",
|
||||
xpre, (ULong)a, xpost );
|
||||
}
|
||||
break;
|
||||
|
||||
case Addr_Stack:
|
||||
emit( "%sAddress 0x%llx is on thread %d's stack%s\n",
|
||||
xpre, (ULong)a, ai->Addr.Stack.tid, xpost );
|
||||
break;
|
||||
|
||||
case Addr_Block: {
|
||||
SizeT block_szB = ai->Addr.Block.block_szB;
|
||||
PtrdiffT rwoffset = ai->Addr.Block.rwoffset;
|
||||
SizeT delta;
|
||||
const HChar* relative;
|
||||
|
||||
if (rwoffset < 0) {
|
||||
delta = (SizeT)(-rwoffset);
|
||||
relative = "before";
|
||||
} else if (rwoffset >= block_szB) {
|
||||
delta = rwoffset - block_szB;
|
||||
relative = "after";
|
||||
} else {
|
||||
delta = rwoffset;
|
||||
relative = "inside";
|
||||
}
|
||||
emit(
|
||||
"%sAddress 0x%lx is %'lu bytes %s a %s of size %'lu %s%s\n",
|
||||
xpre,
|
||||
a, delta, relative, ai->Addr.Block.block_desc,
|
||||
block_szB,
|
||||
ai->Addr.Block.block_kind==Block_Mallocd ? "alloc'd"
|
||||
: ai->Addr.Block.block_kind==Block_Freed ? "free'd"
|
||||
: "client-defined",
|
||||
xpost
|
||||
);
|
||||
if (ai->Addr.Block.block_kind==Block_Mallocd) {
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
|
||||
}
|
||||
else if (ai->Addr.Block.block_kind==Block_Freed) {
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
|
||||
if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
|
||||
emit(
|
||||
"%s block was alloc'd at%s\n",
|
||||
xpre,
|
||||
xpost
|
||||
);
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// client-defined
|
||||
VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
|
||||
tl_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
|
||||
/* Nb: cannot have a freed_at, as a freed client-defined block
|
||||
has a Block_Freed block_kind. */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Addr_DataSym:
|
||||
emit( "%sAddress 0x%llx is %llu bytes "
|
||||
"inside data symbol \"%pS\"%s\n",
|
||||
xpre,
|
||||
(ULong)a,
|
||||
(ULong)ai->Addr.DataSym.offset,
|
||||
ai->Addr.DataSym.name,
|
||||
xpost );
|
||||
break;
|
||||
|
||||
case Addr_Variable:
|
||||
/* Note, no need for XML tags here, because descr1/2 will
|
||||
already have <auxwhat> or <xauxwhat>s on them, in XML
|
||||
mode. */
|
||||
if (ai->Addr.Variable.descr1)
|
||||
emit( "%s%s\n",
|
||||
VG_(clo_xml) ? " " : " ",
|
||||
(HChar*)VG_(indexXA)(ai->Addr.Variable.descr1, 0) );
|
||||
if (ai->Addr.Variable.descr2)
|
||||
emit( "%s%s\n",
|
||||
VG_(clo_xml) ? " " : " ",
|
||||
(HChar*)VG_(indexXA)(ai->Addr.Variable.descr2, 0) );
|
||||
break;
|
||||
|
||||
case Addr_SectKind:
|
||||
emit( "%sAddress 0x%llx is in the %pS segment of %pS%s\n",
|
||||
xpre,
|
||||
(ULong)a,
|
||||
VG_(pp_SectKind)(ai->Addr.SectKind.kind),
|
||||
ai->Addr.SectKind.objname,
|
||||
xpost );
|
||||
break;
|
||||
|
||||
default:
|
||||
VG_(tool_panic)("mc_pp_AddrInfo");
|
||||
}
|
||||
}
|
||||
|
||||
static const HChar* str_leak_lossmode ( Reachedness lossmode )
|
||||
{
|
||||
const HChar *loss = "?";
|
||||
@@ -667,8 +480,8 @@ void MC_(pp_Error) ( Error* err )
|
||||
extra->Err.MemParam.isAddrErr
|
||||
? "unaddressable" : "uninitialised" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err),
|
||||
&extra->Err.MemParam.ai, False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
|
||||
&extra->Err.MemParam.ai, False);
|
||||
if (extra->Err.MemParam.origin_ec
|
||||
&& !extra->Err.MemParam.isAddrErr)
|
||||
mc_pp_origin( extra->Err.MemParam.origin_ec,
|
||||
@@ -679,8 +492,8 @@ void MC_(pp_Error) ( Error* err )
|
||||
extra->Err.MemParam.isAddrErr
|
||||
? "unaddressable" : "uninitialised" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err),
|
||||
&extra->Err.MemParam.ai, False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
|
||||
&extra->Err.MemParam.ai, False);
|
||||
if (extra->Err.MemParam.origin_ec
|
||||
&& !extra->Err.MemParam.isAddrErr)
|
||||
mc_pp_origin( extra->Err.MemParam.origin_ec,
|
||||
@@ -698,8 +511,8 @@ void MC_(pp_Error) ( Error* err )
|
||||
extra->Err.User.isAddrErr
|
||||
? "Unaddressable" : "Uninitialised" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.User.ai,
|
||||
False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai,
|
||||
False);
|
||||
if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
|
||||
mc_pp_origin( extra->Err.User.origin_ec,
|
||||
extra->Err.User.otag & 3 );
|
||||
@@ -708,8 +521,8 @@ void MC_(pp_Error) ( Error* err )
|
||||
extra->Err.User.isAddrErr
|
||||
? "Unaddressable" : "Uninitialised" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err), &extra->Err.User.ai,
|
||||
False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai,
|
||||
False);
|
||||
if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
|
||||
mc_pp_origin( extra->Err.User.origin_ec,
|
||||
extra->Err.User.otag & 3 );
|
||||
@@ -722,13 +535,13 @@ void MC_(pp_Error) ( Error* err )
|
||||
emit( " <what>Invalid free() / delete / delete[]"
|
||||
" / realloc()</what>\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.Free.ai, False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.Free.ai, False );
|
||||
} else {
|
||||
emit( "Invalid free() / delete / delete[] / realloc()\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.Free.ai, False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.Free.ai, False );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -737,13 +550,13 @@ void MC_(pp_Error) ( Error* err )
|
||||
emit( " <kind>MismatchedFree</kind>\n" );
|
||||
emit( " <what>Mismatched free() / delete / delete []</what>\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err),
|
||||
&extra->Err.FreeMismatch.ai, False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
|
||||
&extra->Err.FreeMismatch.ai, False);
|
||||
} else {
|
||||
emit( "Mismatched free() / delete / delete []\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo(VG_(get_error_address)(err),
|
||||
&extra->Err.FreeMismatch.ai, False);
|
||||
VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
|
||||
&extra->Err.FreeMismatch.ai, False);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -755,18 +568,18 @@ void MC_(pp_Error) ( Error* err )
|
||||
extra->Err.Addr.isWrite ? "write" : "read",
|
||||
extra->Err.Addr.szB );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.Addr.ai,
|
||||
extra->Err.Addr.maybe_gcc );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.Addr.ai,
|
||||
extra->Err.Addr.maybe_gcc );
|
||||
} else {
|
||||
emit( "Invalid %s of size %ld\n",
|
||||
extra->Err.Addr.isWrite ? "write" : "read",
|
||||
extra->Err.Addr.szB );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.Addr.ai,
|
||||
extra->Err.Addr.maybe_gcc );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.Addr.ai,
|
||||
extra->Err.Addr.maybe_gcc );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -776,13 +589,13 @@ void MC_(pp_Error) ( Error* err )
|
||||
emit( " <what>Jump to the invalid address stated "
|
||||
"on the next line</what>\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err), &extra->Err.Jump.ai,
|
||||
False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai,
|
||||
False );
|
||||
} else {
|
||||
emit( "Jump to the invalid address stated on the next line\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err), &extra->Err.Jump.ai,
|
||||
False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai,
|
||||
False );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -824,13 +637,13 @@ void MC_(pp_Error) ( Error* err )
|
||||
emit( " <kind>InvalidMemPool</kind>\n" );
|
||||
emit( " <what>Illegal memory pool address</what>\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.IllegalMempool.ai, False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.IllegalMempool.ai, False );
|
||||
} else {
|
||||
emit( "Illegal memory pool address\n" );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
mc_pp_AddrInfo( VG_(get_error_address)(err),
|
||||
&extra->Err.IllegalMempool.ai, False );
|
||||
VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
|
||||
&extra->Err.IllegalMempool.ai, False );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1134,9 +947,6 @@ static Bool mempool_block_maybe_describe( Addr a, AddrInfo* ai );
|
||||
static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
|
||||
{
|
||||
MC_Chunk* mc;
|
||||
ThreadId tid;
|
||||
Addr stack_min, stack_max;
|
||||
VgSectKind sect;
|
||||
|
||||
tl_assert(Addr_Undescribed == ai->tag);
|
||||
|
||||
@@ -1185,78 +995,9 @@ static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
|
||||
ai->Addr.Block.freed_at = MC_(freed_at)(mc);
|
||||
return;
|
||||
}
|
||||
/* -- Perhaps the variable type/location data describes it? -- */
|
||||
ai->Addr.Variable.descr1
|
||||
= VG_(newXA)( VG_(malloc), "mc.da.descr1",
|
||||
VG_(free), sizeof(HChar) );
|
||||
ai->Addr.Variable.descr2
|
||||
= VG_(newXA)( VG_(malloc), "mc.da.descr2",
|
||||
VG_(free), sizeof(HChar) );
|
||||
|
||||
(void) VG_(get_data_description)( ai->Addr.Variable.descr1,
|
||||
ai->Addr.Variable.descr2, a );
|
||||
/* If there's nothing in descr1/2, free them. 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)( ai->Addr.Variable.descr1, 0 ))) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr1 );
|
||||
ai->Addr.Variable.descr1 = NULL;
|
||||
}
|
||||
if (0 == VG_(strlen)( VG_(indexXA)( ai->Addr.Variable.descr2, 0 ))) {
|
||||
VG_(deleteXA)( ai->Addr.Variable.descr2 );
|
||||
ai->Addr.Variable.descr2 = NULL;
|
||||
}
|
||||
/* Assume (assert) that VG_(get_data_description) fills in descr1
|
||||
before it fills in descr2 */
|
||||
if (ai->Addr.Variable.descr1 == NULL)
|
||||
tl_assert(ai->Addr.Variable.descr2 == NULL);
|
||||
/* So did we get lucky? */
|
||||
if (ai->Addr.Variable.descr1 != NULL) {
|
||||
ai->tag = Addr_Variable;
|
||||
return;
|
||||
}
|
||||
/* -- Have a look at the low level data symbols - perhaps it's in
|
||||
there. -- */
|
||||
VG_(memset)( &ai->Addr.DataSym.name,
|
||||
0, sizeof(ai->Addr.DataSym.name));
|
||||
if (VG_(get_datasym_and_offset)(
|
||||
a, &ai->Addr.DataSym.name[0],
|
||||
sizeof(ai->Addr.DataSym.name)-1,
|
||||
&ai->Addr.DataSym.offset )) {
|
||||
ai->tag = Addr_DataSym;
|
||||
tl_assert( ai->Addr.DataSym.name
|
||||
[ sizeof(ai->Addr.DataSym.name)-1 ] == 0);
|
||||
return;
|
||||
}
|
||||
/* -- Perhaps it's on a thread's stack? -- */
|
||||
VG_(thread_stack_reset_iter)(&tid);
|
||||
while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
|
||||
if (stack_min - VG_STACK_REDZONE_SZB <= a && a <= stack_max) {
|
||||
ai->tag = Addr_Stack;
|
||||
ai->Addr.Stack.tid = tid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* -- last ditch attempt at classification -- */
|
||||
tl_assert( sizeof(ai->Addr.SectKind.objname) > 4 );
|
||||
VG_(memset)( &ai->Addr.SectKind.objname,
|
||||
0, sizeof(ai->Addr.SectKind.objname));
|
||||
VG_(strcpy)( ai->Addr.SectKind.objname, "???" );
|
||||
sect = VG_(DebugInfo_sect_kind)( &ai->Addr.SectKind.objname[0],
|
||||
sizeof(ai->Addr.SectKind.objname)-1, a);
|
||||
if (sect != Vg_SectUnknown) {
|
||||
ai->tag = Addr_SectKind;
|
||||
ai->Addr.SectKind.kind = sect;
|
||||
tl_assert( ai->Addr.SectKind.objname
|
||||
[ sizeof(ai->Addr.SectKind.objname)-1 ] == 0);
|
||||
return;
|
||||
}
|
||||
/* -- Clueless ... -- */
|
||||
ai->tag = Addr_Unknown;
|
||||
return;
|
||||
/* No block found. Search a non-heap block description. */
|
||||
VG_(describe_addr) (a, ai);
|
||||
}
|
||||
|
||||
void MC_(pp_describe_addr) ( Addr a )
|
||||
@@ -1265,7 +1006,7 @@ void MC_(pp_describe_addr) ( Addr a )
|
||||
|
||||
ai.tag = Addr_Undescribed;
|
||||
describe_addr (a, &ai);
|
||||
mc_pp_AddrInfo (a, &ai, /* maybe_gcc */ False);
|
||||
VG_(pp_addrinfo_mc) (a, &ai, /* maybe_gcc */ False);
|
||||
}
|
||||
|
||||
/* Fill in *origin_ec as specified by otag, or NULL it out if otag
|
||||
|
||||
@@ -5536,8 +5536,7 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
case 1: { /* get_vbits */
|
||||
Addr address;
|
||||
SizeT szB = 1;
|
||||
VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
|
||||
if (szB != 0) {
|
||||
if (VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr)) {
|
||||
UChar vbits;
|
||||
Int i;
|
||||
Int unaddressable = 0;
|
||||
@@ -5671,8 +5670,8 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
Int kwdid = VG_(keyword_id)
|
||||
("noaccess undefined defined Definedifaddressable",
|
||||
VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
|
||||
VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
|
||||
if (address == (Addr) 0 && szB == 0) return True;
|
||||
if (!VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr))
|
||||
return True;
|
||||
switch (kwdid) {
|
||||
case -2: break;
|
||||
case -1: break;
|
||||
@@ -5700,8 +5699,8 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
Int kwdid = VG_(keyword_id)
|
||||
("addressable defined",
|
||||
VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
|
||||
VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
|
||||
if (address == (Addr) 0 && szB == 0) return True;
|
||||
if (!VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr))
|
||||
return True;
|
||||
switch (kwdid) {
|
||||
case -2: break;
|
||||
case -1: break;
|
||||
@@ -5775,7 +5774,8 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
Addr address;
|
||||
SizeT szB = 1;
|
||||
|
||||
VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
|
||||
if (!VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr))
|
||||
return True;
|
||||
if (address == (Addr) 0) {
|
||||
VG_(gdb_printf) ("Cannot search who points at 0x0\n");
|
||||
return True;
|
||||
@@ -6884,6 +6884,7 @@ static void mc_pre_clo_init(void)
|
||||
VG_(needs_sanity_checks) (mc_cheap_sanity_check,
|
||||
mc_expensive_sanity_check);
|
||||
VG_(needs_print_stats) (mc_print_stats);
|
||||
VG_(needs_info_location) (MC_(pp_describe_addr));
|
||||
VG_(needs_malloc_replacement) (MC_(malloc),
|
||||
MC_(__builtin_new),
|
||||
MC_(__builtin_vec_new),
|
||||
|
||||
@@ -16,7 +16,7 @@ int main(int argc, char *argv[])
|
||||
/* Verify that access via a dangling pointer to a big block bigger than
|
||||
the free list is found by memcheck (still on the free list). */
|
||||
semi_big = malloc (900000);
|
||||
big = malloc (1000001);
|
||||
big = malloc (1000015);
|
||||
free(semi_big);
|
||||
free(big);
|
||||
if (big[1000] > 0x0) jumped();
|
||||
@@ -36,7 +36,7 @@ int main(int argc, char *argv[])
|
||||
big = NULL;
|
||||
|
||||
{
|
||||
big = malloc (1000001);
|
||||
big = malloc (1000015);
|
||||
free(big);
|
||||
if (small[10] > 0x0) jumped();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: main (big_blocks_freed_list.c:22)
|
||||
Address 0x........ is 1,000 bytes inside a block of size 1,000,001 free'd
|
||||
Address 0x........ is 1,000 bytes inside a block of size 1,000,015 free'd
|
||||
at 0x........: free (vg_replace_malloc.c:...)
|
||||
by 0x........: main (big_blocks_freed_list.c:21)
|
||||
|
||||
@@ -13,7 +13,7 @@ Invalid read of size 1
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: main (big_blocks_freed_list.c:33)
|
||||
Address 0x........ is not stack'd, malloc'd or (recently) free'd
|
||||
Address 0x........ is 2,000 bytes inside an unallocated block of size 1,000,016 in arena "client"
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: main (big_blocks_freed_list.c:34)
|
||||
@@ -29,7 +29,7 @@ Invalid read of size 1
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: main (big_blocks_freed_list.c:46)
|
||||
Address 0x........ is 10 bytes inside a block of size 1,000,001 free'd
|
||||
Address 0x........ is 10 bytes inside a block of size 1,000,015 free'd
|
||||
at 0x........: free (vg_replace_malloc.c:...)
|
||||
by 0x........: main (big_blocks_freed_list.c:40)
|
||||
|
||||
@@ -42,7 +42,7 @@ Invalid read of size 1
|
||||
|
||||
HEAP SUMMARY:
|
||||
in use at exit: 1,000,000 bytes in 100 blocks
|
||||
total heap usage: 104 allocs, 4 frees, 3,910,002 bytes allocated
|
||||
total heap usage: 104 allocs, 4 frees, 3,910,030 bytes allocated
|
||||
|
||||
For a detailed leak analysis, rerun with: --leak-check=full
|
||||
|
||||
|
||||
Reference in New Issue
Block a user