Allow tools to provide some statistics in suppression list produced at the end

Option -v outputs a list of used suppressions. This only gives
the nr of times a suppression was used.
For a leak search, this only gives the nr of loss records that
have been suppressed, but it does not give additional needed details
to understand more precisely what has been suppressed
(i.e. nr of blocks and nr of bytes).

=> Add in the tool interface update_extra_suppression_use and
print_extra_suppression_info functions to allow the tool to record
additioonal use statistics for a suppression. These statistics
can be done depending on the error (and its data) which is suppressed.

Use this in memcheck for the leak suppressions, to maintain and output
the nr of blocks and bytes suppressed by a suppression during
the last leak search.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13651
This commit is contained in:
Philippe Waroquiers 2013-10-17 22:10:41 +00:00
parent 5c16367f0c
commit 619be966db
18 changed files with 189 additions and 20 deletions

9
NEWS
View File

@ -32,6 +32,12 @@ Release 3.9.0 (?? ?????? 201?)
for 'use after free' errors or to decrease Valgrind memory and/or cpu usage
by recording less information for heap blocks.
- The list of used suppressions (shown when giving the -v option)
now shows for the leak suppressions how many blocks and bytes were
suppressed during the last leak search for each suppression.
The suppression count for a leak suppression shows the total nr
of loss records which were suppressed by this suppression.
* ==================== OTHER CHANGES ====================
- Option --merge-recursive-frames=<number> tells Valgrind to
@ -63,6 +69,9 @@ Release 3.9.0 (?? ?????? 201?)
'v.do expensive_sanity_check_general' that checks the sanity
of various Valgrind aspects, including the Valgrind heap.
- The list of used suppressions (shown when giving the -v option)
now gives the filename and linenr where the suppression is defined.
- remote debuginfo server + overhaul of debuginfo reading
- some fixes for OSX 10.8

View File

@ -913,12 +913,19 @@ static Bool show_used_suppressions ( void )
" </pair>\n",
su->count, su->sname );
} else {
HChar xtra[256]; /* assumed big enough (is overrun-safe) */
Bool anyXtra;
// blank line before the first shown suppression, if any
if (!any_supp)
VG_(dmsg)("\n");
VG_(dmsg)("used_suppression: %6d %s %s:%d\n", su->count, su->sname,
VG_(memset)(xtra, 0, sizeof(xtra));
anyXtra = VG_TDICT_CALL(tool_print_extra_suppression_use,
su, xtra, sizeof(xtra));
vg_assert(xtra[sizeof(xtra)-1] == 0);
VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
VG_(clo_suppressions)[su->clo_suppressions_i],
su->sname_lineno);
su->sname_lineno,
anyXtra ? " " : "", xtra);
}
any_supp = True;
}
@ -1659,8 +1666,9 @@ static Supp* is_suppressible_error ( Error* err )
/* Conceptually, ip2fo contains an array of function names and an array of
object names, corresponding to the array of IP of err->where.
These names are just computed 'on demand' (so once maximum),
then stored (efficiently, avoiding too many allocs) in ip2fo to be re-usable
for the matching of the same IP with the next suppression pattern.
then stored (efficiently, avoiding too many allocs) in ip2fo to be
re-usable for the matching of the same IP with the next suppression
pattern.
VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
of its arguments. It will then pass it to the function
@ -1687,7 +1695,10 @@ static Supp* is_suppressible_error ( Error* err )
em_supplist_cmps++;
if (supp_matches_error(su, err)
&& supp_matches_callers(&ip2fo, su)) {
/* got a match. Move this entry to the head of the list
/* got a match. */
/* Inform the tool that err is suppressed by su. */
(void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
/* Move this entry to the head of the list
in the hope of making future searches cheaper. */
if (su_prev) {
vg_assert(su_prev->next == su);

View File

@ -234,7 +234,9 @@ void VG_(needs_tool_errors)(
Bool (*read_extra) (Int, HChar**, SizeT*, Int*, Supp*),
Bool (*matches) (Error*, Supp*),
const HChar* (*name) (Error*),
Bool (*get_xtra_si)(Error*,/*OUT*/HChar*,Int)
Bool (*get_xtra_si)(Error*,/*OUT*/HChar*,Int),
Bool (*print_xtra_su)(Supp*,/*OUT*/HChar*,Int),
void (*update_xtra_su)(Error*, Supp*)
)
{
VG_(needs).tool_errors = True;
@ -248,6 +250,8 @@ void VG_(needs_tool_errors)(
VG_(tdict).tool_error_matches_suppression = matches;
VG_(tdict).tool_get_error_name = name;
VG_(tdict).tool_get_extra_suppression_info = get_xtra_si;
VG_(tdict).tool_print_extra_suppression_use = print_xtra_su;
VG_(tdict).tool_update_extra_suppression_use = update_xtra_su;
}
void VG_(needs_command_line_options)(

View File

@ -127,6 +127,8 @@ typedef struct {
Bool (*tool_error_matches_suppression) (Error*, Supp*);
const HChar* (*tool_get_error_name) (Error*);
Bool (*tool_get_extra_suppression_info) (Error*,/*OUT*/HChar*,Int);
Bool (*tool_print_extra_suppression_use) (Supp*,/*OUT*/HChar*,Int);
void (*tool_update_extra_suppression_use) (Error*, Supp*);
// VG_(needs).superblock_discards
void (*tool_discard_superblock_info)(Addr64, VexGuestExtents);

View File

@ -384,14 +384,17 @@ suppression mechanism is designed to allow precise yet flexible
specification of errors to suppress.</para>
<para>If you use the <option>-v</option> option, at the end of execution,
Valgrind prints out one line for each used suppression, giving its name
and the number of times it got used. Here's the suppressions used by a
run of <computeroutput>valgrind --tool=memcheck ls -l</computeroutput>:</para>
Valgrind prints out one line for each used suppression, giving the number of times
it got used, its name and the filename and line number where the suppression is
defined. Depending on the suppression kind, the filename and line number are optionally
followed by additional information (such as the number of blocks and bytes suppressed
by a memcheck leak suppression). Here's the suppressions used by a
run of <computeroutput>valgrind -v --tool=memcheck ls -l</computeroutput>:</para>
<programlisting><![CDATA[
--27579-- supp: 1 socketcall.connect(serv_addr)/__libc_connect/__nscd_getgrgid_r
--27579-- supp: 1 socketcall.connect(serv_addr)/__libc_connect/__nscd_getpwuid_r
--27579-- supp: 6 strrchr/_dl_map_object_from_fd/_dl_map_object]]></programlisting>
--1610-- used_suppression: 2 dl-hack3-cond-1 /usr/lib/valgrind/default.supp:1234
--1610-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a /usr/lib/valgrind/default.supp:1234
]]></programlisting>
<para>Multiple suppressions files are allowed. By default, Valgrind
uses <filename>$PREFIX/lib/valgrind/default.supp</filename>. You can

View File

@ -608,6 +608,19 @@ Bool drd_get_extra_suppression_info(Error* e,
return False;
}
static
Bool drd_print_extra_suppression_use(Supp* su,
/*OUT*/HChar* buf, Int nBuf)
{
return False;
}
static
void drd_update_extra_suppresion_use(Error* e, Supp* supp)
{
return;
}
/** Tell the Valgrind core about DRD's error handlers. */
void DRD_(register_error_handlers)(void)
{
@ -620,5 +633,7 @@ void DRD_(register_error_handlers)(void)
drd_read_extra_suppression_info,
drd_error_matches_suppression,
drd_get_error_name,
drd_get_extra_suppression_info);
drd_get_extra_suppression_info,
drd_print_extra_suppression_use,
drd_update_extra_suppresion_use);
}

View File

@ -793,6 +793,16 @@ Bool pc_get_extra_suppression_info ( Error* err,
}
}
Bool pc_print_extra_suppression_use ( Supp* su,
/*OUT*/HChar* buf, Int nBuf )
{
return False;
}
void pc_update_extra_suppression_use (Error* err, Supp* su)
{
return;
}
/*--------------------------------------------------------------------*/
/*--- end pc_common.c ---*/

View File

@ -58,6 +58,9 @@ Bool pc_error_matches_suppression (Error* err, Supp* su);
const HChar* pc_get_error_name ( Error* err );
Bool pc_get_extra_suppression_info ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
Bool pc_print_extra_suppression_use ( Supp* su,
/*OUT*/HChar* buf, Int nBuf );
void pc_update_extra_suppression_use (Error* err, Supp* su);
extern Bool h_clo_partial_loads_ok;
/* extern Bool h_clo_lossage_check; */

View File

@ -105,7 +105,9 @@ static void pc_pre_clo_init(void)
pc_read_extra_suppression_info,
pc_error_matches_suppression,
pc_get_error_name,
pc_get_extra_suppression_info);
pc_get_extra_suppression_info,
pc_print_extra_suppression_use,
pc_update_extra_suppression_use);
VG_(needs_xml_output) ();

View File

@ -1396,6 +1396,19 @@ Bool HG_(get_extra_suppression_info) ( Error* err,
return False;
}
Bool HG_(print_extra_suppression_use) ( Supp* su,
/*OUT*/HChar* buf, Int nBuf )
{
/* Do nothing */
return False;
}
void HG_(update_extra_suppression_use) ( Error* err, Supp* su )
{
/* Do nothing */
return;
}
/*--------------------------------------------------------------------*/
/*--- end hg_errors.c ---*/

View File

@ -46,6 +46,9 @@ Bool HG_(error_matches_suppression) ( Error* err, Supp* su );
const HChar* HG_(get_error_name) ( Error* err );
Bool HG_(get_extra_suppression_info) ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
Bool HG_(print_extra_suppression_use) ( Supp* su,
/*OUT*/HChar* buf, Int nBuf );
void HG_(update_extra_suppression_use) ( Error* err, Supp* su );
/* Functions for recording various kinds of errors. */
void HG_(record_error_Race) ( Thread* thr,

View File

@ -5286,7 +5286,9 @@ static void hg_pre_clo_init ( void )
HG_(read_extra_suppression_info),
HG_(error_matches_suppression),
HG_(get_error_name),
HG_(get_extra_suppression_info));
HG_(get_extra_suppression_info),
HG_(print_extra_suppression_use),
HG_(update_extra_suppression_use));
VG_(needs_xml_output) ();

View File

@ -343,7 +343,20 @@ extern void VG_(needs_tool_errors) (
// do nothing, and return False. This function is the inverse of
// VG_(tdict).tool_read_extra_suppression_info().
Bool (*print_extra_suppression_info)(Error* err,
/*OUT*/HChar* buf, Int nBuf)
/*OUT*/HChar* buf, Int nBuf),
// This is similar to print_extra_suppression_info, but is used
// to print information such as additional statistical counters
// as part of the used suppression list produced by -v.
Bool (*print_extra_suppression_use)(Supp* su,
/*OUT*/HChar* buf, Int nBuf),
// Called by error mgr once it has been established that err
// is suppressed by su. update_extra_suppression_use typically
// can be used to update suppression extra information such as
// some statistical counters that will be printed by
// print_extra_suppression_use.
void (*update_extra_suppression_use)(Error* err, Supp* su)
);
/* Is information kept by the tool about specific instructions or

View File

@ -1166,11 +1166,28 @@ leak kinds are matched by this suppression entry.
<computeroutput>&lt;set&gt;</computeroutput> is specified similarly
to the option <option>--show-leak-kinds</option>.
If this optional extra line is not present, the suppression entry will match
all leak kinds.
</para>
all leak kinds. </para>
<para>The other memcheck error kinds do not have extra lines.</para>
<para>
If you give the <option>-v</option> option, Valgrind will print
the list of used suppressions at the end of the execution.
For a leak suppression, this output gives the number of different
loss records that matches the suppression, the number of bytes
and blocks suppressed by the suppressions.
In case several leak searches are done, the number of bytes and blocks
are reset to 0 before a new leak search. Note that the number of different
loss records is not reset to 0.
<para>In the example below, in the last leak search, 7 blocks and 96 bytes have
been suppressed by the <option>some_leak_suppression</option>
suppression. </para>
<programlisting><![CDATA[
--21041-- used_suppression: 10 some_other_leak_suppression s.supp:14 suppressed: 12,400 bytes in 1 blocks
--21041-- used_suppression: 39 some_leak_suppression s.supp:2 suppressed: 96 bytes in 7 blocks
]]></programlisting>
</para>
<para>The first line of the calling context: for <varname>ValueN</varname>
and <varname>AddrN</varname> errors, it is either the name of the function
in which the error occurred, or, failing that, the full path of the

View File

@ -1532,6 +1532,14 @@ typedef struct _MC_LeakSuppExtra MC_LeakSuppExtra;
struct _MC_LeakSuppExtra {
UInt match_leak_kinds;
/* Maintains nr of blocks and bytes suppressed with this suppression
during the leak search identified by leak_search_gen.
blocks_suppressed and bytes_suppressed are reset to 0 when
used the first time during a leak search. */
SizeT blocks_suppressed;
SizeT bytes_suppressed;
UInt leak_search_gen;
};
Bool MC_(read_extra_suppression_info) ( Int fd, HChar** bufpp,
@ -1549,6 +1557,9 @@ Bool MC_(read_extra_suppression_info) ( Int fd, HChar** bufpp,
MC_LeakSuppExtra* lse;
lse = VG_(malloc)("mc.resi.2", sizeof(MC_LeakSuppExtra));
lse->match_leak_kinds = RallS;
lse->blocks_suppressed = 0;
lse->bytes_suppressed = 0;
lse->leak_search_gen = 0;
VG_(set_supp_extra)(su, lse); // By default, all kinds will match.
eof = VG_(get_line) ( fd, bufpp, nBufp, lineno );
if (eof) return True; // old LeakSupp style, no match-leak-kinds line.
@ -1617,6 +1628,13 @@ Bool MC_(error_matches_suppression) ( Error* err, Supp* su )
case LeakSupp:
if (ekind == Err_Leak) {
MC_LeakSuppExtra* lse = (MC_LeakSuppExtra*) VG_(get_supp_extra)(su);
if (lse->leak_search_gen != MC_(leak_search_gen)) {
// First time we see this suppression during this leak search.
// => reset the counters to 0.
lse->blocks_suppressed = 0;
lse->bytes_suppressed = 0;
lse->leak_search_gen = MC_(leak_search_gen);
}
return RiS(extra->Err.Leak.lr->key.state, lse->match_leak_kinds);
} else
return False;
@ -1695,6 +1713,37 @@ Bool MC_(get_extra_suppression_info) ( Error* err,
}
}
Bool MC_(print_extra_suppression_use) ( Supp *su,
/*OUT*/HChar *buf, Int nBuf )
{
if (VG_(get_supp_kind)(su) == LeakSupp) {
MC_LeakSuppExtra *lse = (MC_LeakSuppExtra*) VG_(get_supp_extra) (su);
if (lse->leak_search_gen == MC_(leak_search_gen)
&& lse->blocks_suppressed > 0) {
VG_(snprintf) (buf, nBuf-1,
"suppressed: %'lu bytes in %'lu blocks",
lse->bytes_suppressed,
lse->blocks_suppressed);
return True;
} else
return False;
} else
return False;
}
void MC_(update_extra_suppression_use) ( Error* err, Supp* su)
{
if (VG_(get_supp_kind)(su) == LeakSupp) {
MC_LeakSuppExtra *lse = (MC_LeakSuppExtra*) VG_(get_supp_extra) (su);
MC_Error* extra = VG_(get_error_extra)(err);
tl_assert (lse->leak_search_gen = MC_(leak_search_gen));
lse->blocks_suppressed += extra->Err.Leak.lr->num_blocks;
lse->bytes_suppressed
+= extra->Err.Leak.lr->szB + extra->Err.Leak.lr->indirect_szB;
}
}
/*--------------------------------------------------------------------*/
/*--- end mc_errors.c ---*/

View File

@ -351,6 +351,10 @@ typedef
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams * lcp);
// Each time a leak search is done, the leak search generation
// MC_(leak_search_gen) is incremented.
extern UInt MC_(leak_search_gen);
// maintains the lcp.deltamode given in the last call to detect_memory_leaks
extern LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
@ -404,6 +408,9 @@ Bool MC_(error_matches_suppression) ( Error* err, Supp* su );
Bool MC_(get_extra_suppression_info) ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
Bool MC_(print_extra_suppression_use) ( Supp* su,
/*OUT*/HChar* buf, Int nBuf );
void MC_(update_extra_suppression_use) ( Error* err, Supp* su );
const HChar* MC_(get_error_name) ( Error* err );

View File

@ -474,6 +474,10 @@ static UInt detect_memory_leaks_last_heuristics;
// The below avoids replicating the delta_mode in each LossRecord.
LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
// Each leak search run increments the below generation counter.
// A used suppression during a leak search will contain this
// generation number.
UInt MC_(leak_search_gen);
// Records chunks that are currently being processed. Each element in the
// stack is an index into lc_chunks and lc_extras. Its size is
@ -1646,7 +1650,7 @@ void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams* lcp)
// before checking for (smaller) page skipping.
tl_assert((SM_SIZE % VKI_PAGE_SIZE) == 0);
MC_(leak_search_gen)++;
MC_(detect_memory_leaks_last_delta_mode) = lcp->deltamode;
detect_memory_leaks_last_heuristics = lcp->heuristics;

View File

@ -6699,7 +6699,9 @@ static void mc_pre_clo_init(void)
MC_(read_extra_suppression_info),
MC_(error_matches_suppression),
MC_(get_error_name),
MC_(get_extra_suppression_info));
MC_(get_extra_suppression_info),
MC_(print_extra_suppression_use),
MC_(update_extra_suppression_use));
VG_(needs_libc_freeres) ();
VG_(needs_command_line_options)(mc_process_cmd_line_options,
mc_print_usage,