You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
|
1
(13) |
2
(15) |
|
3
(16) |
4
(42) |
5
(9) |
6
(20) |
7
(22) |
8
(24) |
9
(12) |
|
10
(24) |
11
(11) |
12
(2) |
13
(13) |
14
(8) |
15
|
16
(16) |
|
17
(24) |
18
(36) |
19
(100) |
20
(94) |
21
(50) |
22
(39) |
23
(10) |
|
24
(14) |
25
(19) |
26
(2) |
27
(6) |
28
(17) |
29
(9) |
30
(8) |
|
31
(21) |
|
|
|
|
|
|
|
From: Philippe W. <phi...@sk...> - 2009-05-16 23:15:06
|
>> With this "releasedSize", the current memory usage of the heap can be examined in kcachegrind >> by using the cost "allocSize - releasedSize" >> This will allow to see which stack trace "keeps" a lot of memory. > > Yes. Note that the minus operator currently is not supported in KCachegrind, > but that should be easy to fix... With the versions I am using, minus operator seems supported : I have tested on kcachegrind 0.4.6 on portable ubuntu for windows (an ubuntu running as a windows process) and the minus operator (at least in an event type defined inside kcachegrind) using "new event type" is working. I will retry with the kcachegrind 0.5.0 version on fedora 10 but IIRC, it also works under fedora. > Hmm.. Not sure about the "twice" and the "self" (should work). I have somewhat cleaned up the first quick and dirty implementation I did (for allocSize and freeSize), With your info that it should work at least for the self, I will re-introduce the releasedSize and double-check what it gives. > To be honest, the best way is not really clear for me, too. Storing the callstack > for every allocation, and propagating "releasedSize" at free time, seems to be > a very resource-expensive way (both in space & time), and probably is not working > at all for big codes. For the heap related events (malloc/free), the explosion should be reasonable, (as this is the technique used by memcheck/massif to report errors: both are associating to each heap block a pointer to a stack trace). So, at least in terms of stack trace size, I imagine that a callstack of JCC for each allocation should work. (using an hash table to share the identical JCC callstacks to avoid duplication). But this solution can only work for a "small subset" of all the possible stack traces in a huge program (and even small programs can create a huge nr of different stack traces; cfr the test program in the valgrind bug 191182). I understand there is a need for a more general solution (such as the below), that will work for other cases having a much bigger nr of stack traces than heap events. > I would like to extend KCachegrind to come up with inclusive costs itself, if they > are not provided by the measurement tool, using calling contexts. This is > needed to visulize data from other measurement tools (such as sampling tools which > can provide length-limited calling contexts for every sample), so ... > > Perhaps there is not much to do in Callgrind at all. Just writing more detailed > contexts from Callgrind (as is already possible with --separate-callers=<n>), > and ignore the issue of inclusive costs for "releasedSize". > > However, KCachegrind needs to be extended as written above. > > KCachegrind currently makes no use at all from calling context information. It > just prints out the concatenation of symbol names in the call chains, as > given by Callgrind... I am not too sure I understand what you describe for kcachegrind based solution, I will re-read, sleep on it, and get back to you probably with more questions. Thanks for your help/advice (and thanks for callgrind/kcachegrind tools) Philippe |
|
From: Josef W. <Jos...@gm...> - 2009-05-16 21:42:36
|
On Friday 15 May 2009, Philippe Waroquiers wrote: > I am working on callgrind to add the capture of alloc/free information events. > > I have now something which starts to work (at least on small examples). > This allows then to use the callgrind/kcachegrind to examine e.g. graphically > the heap memory usage. In other words, this is similar to massif, but integrated > within callgrind and its graphical tool. The result on small examples > looks nice in kcachegrind. > > The events I am currently capturing is: > allocSize (increased by N when N bytes are allocated) > in the callgraph, associated to the callstack that did the alloc > freeSize (increased by N when N bytes are freed). > in the callgraph, associated to the callstack that did the free > (this allows to see who allocates and/or who frees a lot). Nice. > To this, I would like to add a "releasedSize" event. > The releasedSize will be increased similarly to freeSize but the idea is to associate > this cost to the same callstack that allocated the memory being freed. Ah, Ok. So the idea is to attach an event to a execution context from the past. Unfortunately, this does not play nice with the way inclusive costs currently are captured (see below). > With this "releasedSize", the current memory usage of the heap can be examined in kcachegrind > by using the cost "allocSize - releasedSize" > This will allow to see which stack trace "keeps" a lot of memory. Yes. Note that the minus operator currently is not supported in KCachegrind, but that should be easy to fix... > I have tried a naive (and incorrect) approach to implement releasedSize: > At allocation time, I am saving somewhere the pointer and the bbcc used at allocation. > When the pointer is released, I am retrieving the corresponding bbcc and adding the size > of the block freed to the releasedSize cost of this bbcc. > > At the end of the run, I see that the total releasedSize is incremented (but twice the > nr of bytes freed). Moreover, nothing appears in the "self" or "inclusive" columns > for this event. Hmm.. Not sure about the "twice" and the "self" (should work). However, "inclusive" can not work. In callgrind, inclusive cost is measured using a global, always increasing counter array. For a function f, the inclusive cost is the global counter values when leaving f minus the values when entering it. Now, your update of releasedSize never changes any such global counter, so any inclusive cost will always be zero. But more problematic, there is simply no way to increase a global counter in a way such that this will result in meaningful data with the current strategy. BTW, the "cache use" metrics have the same problem: Only self cost is useful. Would be nice to have a general solution for this. > I guess that I need to do something more complex, like: > * saving a full chain of bbcc (or something like that) at allocation time Something similar to this is already available. A bbcc is releated to a "context", which is unique for a call chain of functions (default is length 1, ie. only the current running function). If you look at new_cxt() in callgrind/context.c, this is the "size" of a context, which currently is given as a setting stored for every function. It would be nice to have every context specifiying the full call chain from main(), but this is simply not feasable, as the number of such contexts explodes with huge codes such as firefox/openoffice; therefore the limit on the call chain length for contexts. Anyway, the inclusive costs are not stored in BBCCs, but in JCCs (with from/to tuples of BBCCs), so for adjusting the inclusive costs, you would need to take these from the current call stack, which is an array of call_entry's (see type call_stack in callgrind/global.h). > * and then propagate the releasedSize on this chain of bbcc Yes, adjust "cost" in the JCCs. However, this can be potentially very expensive. A completely alternative way would be to not adjust any inclusive costs in Callgrind itself for "releasedSize", but make the propagation of costs at postprocessing time in KCachegrind, and for this to be possible, put a more exact calling context of self costs into the output file. > Or maybe save the stack trace (execontext) and "simulate" a call to > propagate the releasedSize ? "simulating a call" will help nothing, as there is no propagation up the call stack done at all. > I have read here and there callgrind code, but it is not clear to me how to attack this. To be honest, the best way is not really clear for me, too. Storing the callstack for every allocation, and propagating "releasedSize" at free time, seems to be a very resource-expensive way (both in space & time), and probably is not working at all for big codes. In contrast, relating allocation to the call context, writing out more detailled contexts with according self cost, and do the propagation in KCachegrind seems to be somehow better, and probably is more the massif way. But then, you only estimate the real inclusive cost (if not every context has the full call chain from main()), and it will not directly be comparable to "allocSize". > Any advice/pointers about how to go/ what to read in detail/ ... ? I would like to extend KCachegrind to come up with inclusive costs itself, if they are not provided by the measurement tool, using calling contexts. This is needed to visulize data from other measurement tools (such as sampling tools which can provide length-limited calling contexts for every sample), so ... Perhaps there is not much to do in Callgrind at all. Just writing more detailed contexts from Callgrind (as is already possible with --separate-callers=<n>), and ignore the issue of inclusive costs for "releasedSize". However, KCachegrind needs to be extended as written above. KCachegrind currently makes no use at all from calling context information. It just prints out the concatenation of symbol names in the call chains, as given by Callgrind... Josef |
|
From: <sv...@va...> - 2009-05-16 10:49:05
|
Author: sewardj
Date: 2009-05-16 11:49:03 +0100 (Sat, 16 May 2009)
New Revision: 9855
Log:
Helgrind and exp-Ptrcheck:
Update calls to VG_(needs_xml_output) to be in accordance with
core/tool iface change committed in r9846/7.
Modified:
branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.h
branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_main.c
branches/MESSAGING_TIDYUP/helgrind/hg_errors.h
branches/MESSAGING_TIDYUP/helgrind/hg_main.c
Modified: branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.h
===================================================================
--- branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.h 2009-05-16 10:46:09 UTC (rev 9854)
+++ branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.h 2009-05-16 10:49:03 UTC (rev 9855)
@@ -47,8 +47,9 @@
void h_record_sysparam_error( ThreadId tid, CorePart part, Char* s,
Addr lo, Addr hi, Seg* seglo, Seg* seghi );
-Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 );
-void pc_pp_Error ( Error* err );
+Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 );
+void pc_before_pp_Error ( Error* err );
+void pc_pp_Error ( Error* err );
UInt pc_update_Error_extra ( Error* err );
Bool pc_is_recognised_suppression ( Char* name, Supp *su );
Bool pc_read_extra_suppression_info ( Int fd, Char* buf,
Modified: branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_main.c
===================================================================
--- branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_main.c 2009-05-16 10:46:09 UTC (rev 9854)
+++ branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_main.c 2009-05-16 10:49:03 UTC (rev 9855)
@@ -185,7 +185,7 @@
pc_get_error_name,
pc_print_extra_suppression_info);
- VG_(needs_xml_output) ();
+ VG_(needs_xml_output) (pc_before_pp_Error);
VG_(needs_syscall_wrapper)( h_pre_syscall,
h_post_syscall );
Modified: branches/MESSAGING_TIDYUP/helgrind/hg_errors.h
===================================================================
--- branches/MESSAGING_TIDYUP/helgrind/hg_errors.h 2009-05-16 10:46:09 UTC (rev 9854)
+++ branches/MESSAGING_TIDYUP/helgrind/hg_errors.h 2009-05-16 10:49:03 UTC (rev 9855)
@@ -35,9 +35,10 @@
/* The standard bundle of error management functions that we are
required to present to the core/tool interface at startup. */
-Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 );
-void HG_(pp_Error) ( Error* err );
-UInt HG_(update_extra) ( Error* err );
+Bool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 );
+void HG_(before_pp_Error) ( Error* err );
+void HG_(pp_Error) ( Error* err );
+UInt HG_(update_extra) ( Error* err );
Bool HG_(recognised_suppression) ( Char* name, Supp *su );
Bool HG_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf,
Supp* su );
Modified: branches/MESSAGING_TIDYUP/helgrind/hg_main.c
===================================================================
--- branches/MESSAGING_TIDYUP/helgrind/hg_main.c 2009-05-16 10:46:09 UTC (rev 9854)
+++ branches/MESSAGING_TIDYUP/helgrind/hg_main.c 2009-05-16 10:49:03 UTC (rev 9855)
@@ -4204,7 +4204,7 @@
HG_(get_error_name),
HG_(print_extra_suppression_info));
- VG_(needs_xml_output) ();
+ VG_(needs_xml_output) (HG_(before_pp_Error));
VG_(needs_command_line_options)(hg_process_cmd_line_option,
hg_print_usage,
|
|
From: <sv...@va...> - 2009-05-16 10:46:15
|
Author: sewardj
Date: 2009-05-16 11:46:09 +0100 (Sat, 16 May 2009)
New Revision: 9854
Log:
Update XML output for Ptrcheck, to sync with Protocol 4 revisions
that were committed in r9853.
Modified:
branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.c
Modified: branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.c
===================================================================
--- branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.c 2009-05-16 10:44:08 UTC (rev 9853)
+++ branches/MESSAGING_TIDYUP/exp-ptrcheck/pc_common.c 2009-05-16 10:46:09 UTC (rev 9854)
@@ -38,6 +38,7 @@
#include "pub_tool_basics.h"
#include "pub_tool_libcbase.h"
#include "pub_tool_libcprint.h"
+#include "pub_tool_xarray.h"
#include "pub_tool_mallocfree.h"
#include "pub_tool_libcassert.h"
#include "pub_tool_options.h"
@@ -133,8 +134,8 @@
Addr addr;
SSizeT sszB; /* -ve is write, +ve is read */
Seg* vseg;
- Char descr1[96];
- Char descr2[96];
+ XArray* descr1; /* XArray* of HChar */
+ XArray* descr2; /* XArray* of HChar */
Char datasym[96];
PtrdiffT datasymoff;
} Heap;
@@ -256,6 +257,13 @@
// //
//////////////////////////////////////////////////////////////
+/* This is the "this error is due to be printed shortly; so have a
+ look at it any print any preamble you want" function. Which, in
+ Ptrcheck, we don't use. Hence a no-op.
+*/
+void pc_before_pp_Error ( Error* err ) {
+}
+
/* Do a printf-style operation on either the XML or normal output
channel, depending on the setting of VG_(clo_xml).
*/
@@ -275,6 +283,13 @@
emit_WRK(format, vargs);
va_end(vargs);
}
+static void emiN ( HChar* format, ... ) /* With NO FORMAT CHECK */
+{
+ va_list vargs;
+ va_start(vargs, format);
+ emit_WRK(format, vargs);
+ va_end(vargs);
+}
static Char* readwrite(SSizeT sszB)
@@ -288,10 +303,7 @@
void pc_pp_Error ( Error* err )
{
- HChar* what_pre = VG_(clo_xml) ? " <what>" : "";
- HChar* what_post = VG_(clo_xml) ? "</what>" : "";
- HChar* auxw_pre = VG_(clo_xml) ? " <auxwhat>" : " ";
- HChar* auxw_post = VG_(clo_xml) ? "</auxwhat>" : "";
+ const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
XError *xe = (XError*)VG_(get_error_extra)(err);
tl_assert(xe);
@@ -300,23 +312,34 @@
//----------------------------------------------------------
case XE_SorG:
- tl_assert(xe);
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>SorG</kind>\n");
- emit( "%sInvalid %s of size %ld%s\n",
- what_pre,
- xe->XE.SorG.sszB < 0 ? "write" : "read",
- Word__abs(xe->XE.SorG.sszB),
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
- emit( "%sAddress %#lx expected vs actual:%s\n",
- auxw_pre, xe->XE.SorG.addr, auxw_post );
- emit( "%sExpected: %s%s\n",
- auxw_pre, &xe->XE.SorG.expect[0], auxw_post );
- emit( "%sActual: %s%s\n",
- auxw_pre, &xe->XE.SorG.actual[0], auxw_post );
+ emit( " <kind>SorG</kind>\n");
+ emit( " <what>Invalid %s of size %ld</what>\n",
+ xe->XE.SorG.sszB < 0 ? "write" : "read",
+ Word__abs(xe->XE.SorG.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " <auxwhat>Address %#lx expected vs actual:</auxwhat>\n",
+ xe->XE.SorG.addr );
+ emiN( " <auxwhat>Expected: %t</auxwhat>\n",
+ &xe->XE.SorG.expect[0] );
+ emiN( " <auxwhat>Actual: %t</auxwhat>\n",
+ &xe->XE.SorG.actual[0] );
+
+ } else {
+
+ emit( "Invalid %s of size %ld\n",
+ xe->XE.SorG.sszB < 0 ? "write" : "read",
+ Word__abs(xe->XE.SorG.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
+ emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
+ emit( " Actual: %s\n", &xe->XE.SorG.actual[0] );
+
+ }
break;
//----------------------------------------------------------
@@ -329,16 +352,30 @@
if (NONPTR == vseg) {
// Access via a non-pointer
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>Heap</kind>\n");
- emit( "%sInvalid %s of size %ld%s\n",
- what_pre, readwrite(xe->XE.Heap.sszB),
- Word__abs(xe->XE.Heap.sszB), what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- emit( "%sAddress %#lx is not derived from "
- "any known block%s\n",
- auxw_pre, a, auxw_post );
+ if (xml) {
+
+ emit( " <kind>Heap</kind>\n");
+ emit( " <what>Invalid %s of size %ld</what>\n",
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " <auxwhat>Address %#lx is not derived from "
+ "any known block</auxwhat>\n", a );
+
+ } else {
+
+ emit( "Invalid %s of size %ld\n",
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is not derived from "
+ "any known block\n", a );
+
+ }
+
} else {
// Access via a pointer, but outside its range.
Int cmp;
@@ -351,32 +388,77 @@
? "Doubly-invalid" : "Invalid" );
legit = ( Seg__is_freed(vseg) ? "once-" : "" );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>Heap</kind>\n");
- emit( "%s%s %s of size %ld%s\n",
- what_pre, how_invalid,
- readwrite(xe->XE.Heap.sszB),
- Word__abs(xe->XE.Heap.sszB), what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
- emit( "%sAddress %#lx is %lu bytes %s the accessing pointer's%s\n",
- auxw_pre, a, miss_size, place , auxw_post );
- emit( "%s%slegitimate range, a block of size %lu %s%s\n",
- auxw_pre, legit, Seg__size(vseg),
- Seg__is_freed(vseg) ? "free'd" : "alloc'd", auxw_post );
- VG_(pp_ExeContext)(Seg__where(vseg));
+ emit( " <kind>Heap</kind>\n");
+ emit( " <what>%s %s of size %ld</what>\n",
+ how_invalid,
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " <auxwhat>Address %#lx is %lu bytes %s "
+ "the accessing pointer's</auxwhat>\n",
+ a, miss_size, place );
+ emit( " <auxwhat>%slegitimate range, "
+ "a block of size %lu %s</auxwhat>\n",
+ legit, Seg__size(vseg),
+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
+ VG_(pp_ExeContext)(Seg__where(vseg));
+
+ } else {
+
+ emit( "%s %s of size %ld\n",
+ how_invalid,
+ readwrite(xe->XE.Heap.sszB),
+ Word__abs(xe->XE.Heap.sszB) );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
+ a, miss_size, place );
+ emit( " %slegitimate range, a block of size %lu %s\n",
+ legit, Seg__size(vseg),
+ Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
+ VG_(pp_ExeContext)(Seg__where(vseg));
+
+ }
}
- if (xe->XE.Heap.descr1[0] != 0)
- emit( "%s%s%s\n", auxw_pre, xe->XE.Heap.descr1, auxw_post );
- if (xe->XE.Heap.descr2[0] != 0)
- emit( "%s%s%s\n", auxw_pre, xe->XE.Heap.descr2, auxw_post );
- if (xe->XE.Heap.datasym[0] != 0)
- emit( "%sAddress 0x%llx is %llu bytes "
- "inside data symbol \"%s\"%s\n",
- auxw_pre,
- (ULong)xe->XE.Heap.addr,
- (ULong)xe->XE.Heap.datasymoff,
- xe->XE.Heap.datasym, auxw_post );
+
+ /* If we have a better description of the address, show it.
+ Note that in XML mode, it will already by nicely wrapped up
+ in tags, either <auxwhat> or <xauxwhat>, so we can just emit
+ it verbatim. */
+ if (xml) {
+
+ if (xe->XE.Heap.descr1)
+ emiN( " %t\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
+ if (xe->XE.Heap.descr2)
+ emiN( " %t\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
+ if (xe->XE.Heap.datasym[0] != 0)
+ emiN( " <auxwhat>Address 0x%llx is %llu bytes "
+ "inside data symbol \"%t\"</auxwhat>\n",
+ (ULong)xe->XE.Heap.addr,
+ (ULong)xe->XE.Heap.datasymoff,
+ xe->XE.Heap.datasym );
+
+ } else {
+
+ if (xe->XE.Heap.descr1)
+ emit( " %s\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
+ if (xe->XE.Heap.descr2)
+ emit( " %s\n",
+ (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
+ if (xe->XE.Heap.datasym[0] != 0)
+ emit( " Address 0x%llx is %llu bytes "
+ "inside data symbol \"%s\"\n",
+ (ULong)xe->XE.Heap.addr,
+ (ULong)xe->XE.Heap.datasymoff,
+ xe->XE.Heap.datasym );
+
+ }
break;
}
@@ -389,35 +471,69 @@
tl_assert(BOTTOM != seg1);
tl_assert(BOTTOM != seg2 && UNKNOWN != seg2);
- if (VG_(clo_xml))
- VG_(printf_xml)(" <kind>Arith</kind>\n");
- emit( "%sInvalid arguments to %s%s\n",
- what_pre, xe->XE.Arith.opname, what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
- if (seg1 != seg2) {
- if (NONPTR == seg1) {
- emit( "%sFirst arg not a pointer%s\n", auxw_pre, auxw_post );
- } else if (UNKNOWN == seg1) {
- emit( "%sFirst arg may be a pointer%s\n", auxw_pre, auxw_post );
+ emit( " <kind>Arith</kind>\n");
+ emit( " <what>Invalid arguments to %s</what>\n",
+ xe->XE.Arith.opname );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (seg1 != seg2) {
+ if (NONPTR == seg1) {
+ emit( " <auxwhat>First arg not a pointer</auxwhat>\n" );
+ } else if (UNKNOWN == seg1) {
+ emit( " <auxwhat>First arg may be a pointer</auxwhat>\n" );
+ } else {
+ emit( " <auxwhat>First arg derived from address %#lx of "
+ "%lu-byte block alloc'd</auxwhat>\n",
+ Seg__addr(seg1), Seg__size(seg1) );
+ VG_(pp_ExeContext)(Seg__where(seg1));
+ }
+ which = "Second arg";
} else {
- emit( "%sFirst arg derived from address %#lx of "
- "%lu-byte block alloc'd%s\n",
- auxw_pre, Seg__addr(seg1), Seg__size(seg1), auxw_post );
- VG_(pp_ExeContext)(Seg__where(seg1));
+ which = "Both args";
}
- which = "Second arg";
+ if (NONPTR == seg2) {
+ emit( " <auxwhat>%s not a pointer</auxwhat>\n", which );
+ } else {
+ emit( " <auxwhat>%s derived from address %#lx of "
+ "%lu-byte block alloc'd</auxwhat>\n",
+ which, Seg__addr(seg2), Seg__size(seg2) );
+ VG_(pp_ExeContext)(Seg__where(seg2));
+ }
+
} else {
- which = "Both args";
+
+ emit( "Invalid arguments to %s\n",
+ xe->XE.Arith.opname );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (seg1 != seg2) {
+ if (NONPTR == seg1) {
+ emit( " First arg not a pointer\n" );
+ } else if (UNKNOWN == seg1) {
+ emit( " First arg may be a pointer\n" );
+ } else {
+ emit( " First arg derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ Seg__addr(seg1), Seg__size(seg1) );
+ VG_(pp_ExeContext)(Seg__where(seg1));
+ }
+ which = "Second arg";
+ } else {
+ which = "Both args";
+ }
+ if (NONPTR == seg2) {
+ emit( " %s not a pointer\n", which );
+ } else {
+ emit( " %s derived from address %#lx of "
+ "%lu-byte block alloc'd\n",
+ which, Seg__addr(seg2), Seg__size(seg2) );
+ VG_(pp_ExeContext)(Seg__where(seg2));
+ }
+
}
- if (NONPTR == seg2) {
- emit( "%s%s not a pointer%s\n", auxw_pre, which, auxw_post );
- } else {
- emit( "%s%s derived from address %#lx of "
- "%lu-byte block alloc'd%s\n",
- auxw_pre, which, Seg__addr(seg2), Seg__size(seg2), auxw_post );
- VG_(pp_ExeContext)(Seg__where(seg2));
- }
+
break;
}
@@ -441,46 +557,87 @@
tl_assert(is_known_segment(seglo));
tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled?
- if (VG_(clo_xml))
- VG_(printf_xml)(" <kind>SysParam</kind>\n");
- emit( "%s%s%s contains unaddressable byte(s)%s\n",
- what_pre, what, s, what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xml) {
- emit( "%sAddress %#lx is %ld bytes inside a "
- "%ld-byte block free'd%s\n",
- auxw_pre, lo, lo-Seg__addr(seglo),
- Seg__size(seglo), auxw_post );
- VG_(pp_ExeContext)(Seg__where(seglo));
- } else {
- // mismatch
- if (VG_(clo_xml))
- VG_(printf_xml)(" <kind>SysParam</kind>\n");
- emit( "%s%s%s is non-contiguous%s\n",
- what_pre, what, s, what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ emit( " <kind>SysParam</kind>\n");
+ emit( " <what>%s%s contains unaddressable byte(s)</what>\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " <auxwhat>Address %#lx is %ld bytes inside a "
+ "%ld-byte block free'd</auxwhat>\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
- if (UNKNOWN == seglo) {
- emit( "%sFirst byte is not inside a known block%s\n",
- auxw_pre, auxw_post );
} else {
- emit( "%sFirst byte (%#lx) is %ld bytes inside a "
- "%ld-byte block alloc'd%s\n",
- auxw_pre, lo, lo-Seg__addr(seglo),
- Seg__size(seglo), auxw_post );
+
+ emit( " %s%s contains unaddressable byte(s)\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ emit( " Address %#lx is %ld bytes inside a "
+ "%ld-byte block free'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
VG_(pp_ExeContext)(Seg__where(seglo));
+
}
- if (UNKNOWN == seghi) {
- emit( "%sLast byte is not inside a known block%s\n",
- auxw_pre, auxw_post );
+ } else {
+ // mismatch
+
+ if (xml) {
+
+ emit( " <kind>SysParam</kind>\n");
+ emit( " <what>%s%s is non-contiguous</what>\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (UNKNOWN == seglo) {
+ emit( " <auxwhat>First byte is "
+ "not inside a known block</auxwhat>\n" );
+ } else {
+ emit( " <auxwhat>First byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd</auxwhat>\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+ }
+
+ if (UNKNOWN == seghi) {
+ emit( " <auxwhat>Last byte is "
+ "not inside a known block</auxwhat>\n" );
+ } else {
+ emit( " <auxwhat>Last byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd</auxwhat>\n",
+ hi, hi-Seg__addr(seghi), Seg__size(seghi) );
+ VG_(pp_ExeContext)(Seg__where(seghi));
+ }
+
} else {
- emit( "%sLast byte (%#lx) is %ld bytes inside a "
- "%ld-byte block alloc'd%s\n",
- auxw_pre, hi, hi-Seg__addr(seghi),
- Seg__size(seghi), auxw_post );
- VG_(pp_ExeContext)(Seg__where(seghi));
+
+ emit( "%s%s is non-contiguous\n",
+ what, s );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (UNKNOWN == seglo) {
+ emit( " First byte is not inside a known block\n" );
+ } else {
+ emit( " First byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ lo, lo-Seg__addr(seglo), Seg__size(seglo) );
+ VG_(pp_ExeContext)(Seg__where(seglo));
+ }
+
+ if (UNKNOWN == seghi) {
+ emit( " Last byte is not inside a known block\n" );
+ } else {
+ emit( " Last byte (%#lx) is %ld bytes inside a "
+ "%ld-byte block alloc'd\n",
+ hi, hi-Seg__addr(seghi), Seg__size(seghi) );
+ VG_(pp_ExeContext)(Seg__where(seghi));
+ }
+
}
+
}
break;
}
@@ -497,38 +654,71 @@
tl_assert(xe);
switch (xe->tag) {
case XE_SorG:
- return sizeof(XError);
+ break;
case XE_Heap: {
- tl_assert(sizeof(xe->XE.Heap.descr1) == sizeof(xe->XE.Heap.descr2));
- tl_assert(sizeof(xe->XE.Heap.descr1) > 0);
+ Bool have_descr;
+
tl_assert(sizeof(xe->XE.Heap.datasym) > 0);
- VG_(memset)(&xe->XE.Heap.descr1, 0, sizeof(xe->XE.Heap.descr1));
- VG_(memset)(&xe->XE.Heap.descr2, 0, sizeof(xe->XE.Heap.descr2));
+ xe->XE.Heap.datasymoff = 0;
+ xe->XE.Heap.datasym[0] = 0;
+
+ tl_assert(!xe->XE.Heap.descr1);
+ tl_assert(!xe->XE.Heap.descr2);
+
+ xe->XE.Heap.descr1
+ = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
+ VG_(free), sizeof(HChar) );
+ xe->XE.Heap.descr2
+ = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
+ VG_(free), sizeof(HChar) );
+
VG_(memset)(&xe->XE.Heap.datasym, 0, sizeof(xe->XE.Heap.datasym));
xe->XE.Heap.datasymoff = 0;
- if (VG_(get_data_description)( &xe->XE.Heap.descr1[0],
- &xe->XE.Heap.descr2[0],
- sizeof(xe->XE.Heap.descr1)-1,
- xe->XE.Heap.addr )) {
- tl_assert(xe->XE.Heap.descr1[sizeof(xe->XE.Heap.descr1)-1] == 0);
- tl_assert(xe->XE.Heap.descr1[sizeof(xe->XE.Heap.descr2)-1] == 0);
+
+ have_descr
+ = VG_(get_data_description)( xe->XE.Heap.descr1,
+ xe->XE.Heap.descr2,
+ xe->XE.Heap.addr );
+
+ /* If there's nothing in descr1/2, free it. Why is it safe to
+ to VG_(indexXA) at zero here? Because
+ VG_(get_data_description) guarantees to zero terminate
+ descr1/2 regardless of the outcome of the call. So there's
+ always at least one element in each XA after the call.
+ */
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr1, 0 ))
+ || !have_descr) {
+ VG_(deleteXA)( xe->XE.Heap.descr1 );
+ xe->XE.Heap.descr1 = NULL;
}
- else
- if (VG_(get_datasym_and_offset)( xe->XE.Heap.addr,
- &xe->XE.Heap.datasym[0],
- sizeof(xe->XE.Heap.datasym)-1,
- &xe->XE.Heap.datasymoff )) {
- tl_assert(xe->XE.Heap.datasym[sizeof(xe->XE.Heap.datasym)-1] == 0);
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr2, 0 ))
+ || !have_descr) {
+ VG_(deleteXA)( xe->XE.Heap.descr2 );
+ xe->XE.Heap.descr2 = NULL;
}
- return sizeof(XError);
+
+ /* If Dwarf3 info produced nothing useful, see at least if
+ we can fish something useful out of the ELF symbol info. */
+ if (!have_descr) {
+ if (VG_(get_datasym_and_offset)(
+ xe->XE.Heap.addr, &xe->XE.Heap.datasym[0],
+ sizeof(xe->XE.Heap.datasym)-1,
+ &xe->XE.Heap.datasymoff )
+ ) {
+ tl_assert(xe->XE.Heap.datasym[sizeof(xe->XE.Heap.datasym)-1]
+ == 0);
+ }
+ }
+ break;
}
case XE_Arith:
- return sizeof(XError);
+ break;
case XE_SysParam:
- return sizeof(XError);
+ break;
default:
VG_(tool_panic)("update_extra");
}
+ return sizeof(XError);
}
Bool pc_is_recognised_suppression ( Char* name, Supp *su )
|
|
From: <sv...@va...> - 2009-05-16 10:44:16
|
Author: sewardj Date: 2009-05-16 11:44:08 +0100 (Sat, 16 May 2009) New Revision: 9853 Log: Update specification for Ptrcheck output, to be in line with overall XML format overhaul committed in r9849. Modified: branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt Modified: branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt =================================================================== --- branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt 2009-05-16 06:24:40 UTC (rev 9852) +++ branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt 2009-05-16 10:44:08 UTC (rev 9853) @@ -537,37 +537,39 @@ ==================================================================== -ERROR definition for Ptrcheck ------------------------------ +TOOLSPECIFIC definition for Ptrcheck +------------------------------------ -The definition is: +For Ptrcheck, a TOOLSPECIFIC is simply an ERROR: - <error> - <unique>HEX64</unique> - <tid>INT</tid> - <kind>KIND</kind> - <what>TEXT</what> (either 1 or 2 times) +TOOLSPECIIFIC = ERROR - STACK - zero or more of (STACK or <auxwhat>TEXT</auxwhat>) +ERROR details for Ptrcheck +-------------------------- - optionally: SUPPRESSION - </error> +The "... tool-specific fields ..." for Ptrcheck consist of +zero or more of "(either AUXWHAT or XAUXWHAT or STACK)". +They should be shown to the user in the order they appear. -The first four fields and the last field are specified in "ERROR -definition -- common fields" above. The remaining fields are as -follows: +Ptrcheck does not produce any XWHAT records, despite the fact that +"ERROR definition -- common structure" says it might do. -* The primary STACK for this error, indicating where it occurred. -* Some error types may have auxiliary information attached, expressed - as an arbitrary sequence of (STACK or <auxwhat>TEXT</auxwhat>). - These should be presented to the user in the sequence they appear in - the file, as they are intended to be read top-to-bottom. +XAUXWHATs (for definition, see above) may contain the following extra +components (along with the mandatory <text>...</text> component): +* <hthreadid>INT</hthreadid>, same meaning as when referred to in + XWHAT +* <file>TEXT</file>, as defined in FRAME + +* <line>INT</line>, as defined in FRAME + +* <dir>TEXT</dir>, as defined in FRAME + + KIND for Ptrcheck ----------------- This is a small enumeration indicating roughly the nature of an error. |
|
From: <sv...@va...> - 2009-05-16 06:24:44
|
Author: bart
Date: 2009-05-16 07:24:40 +0100 (Sat, 16 May 2009)
New Revision: 9852
Log:
Added pth_mutex_reinit regression test.
Added:
trunk/drd/tests/pth_mutex_reinit.c
trunk/drd/tests/pth_mutex_reinit.stderr.exp
trunk/drd/tests/pth_mutex_reinit.vgtest
Modified:
trunk/drd/tests/
trunk/drd/tests/Makefile.am
Property changes on: trunk/drd/tests
___________________________________________________________________
Name: svn:ignore
- *.stderr.diff*
*.stderr.out
*.stdout.diff*
*.stdout.out
.deps
atomic_var
bar_bad
bar_trivial
boost_thread
circular_buffer
drd_bitmap_test
fp_race
hg01_all_ok
hg02_deadlock
hg03_inherit
hg04_race
hg05_race2
hg06_readshared
hold_lock
linuxthreads_det
Makefile
Makefile.in
matinv
memory_allocation
monitor_example
new_delete
omp_matinv
omp_prime
omp_printf
pth_barrier
pth_barrier_race
pth_barrier_reinit
pth_broadcast
pth_cancel_locked
pth_cond_race
pth_create_chain
pth_create_glibc_2_0
pth_detached
pth_detached_sem
pth_inconsistent_cond_wait
pth_process_shared_mutex
pth_spinlock
qt4_mutex
qt4_rwlock
qt4_semaphore
recursive_mutex
rwlock_race
rwlock_test
sem_as_mutex
sigalrm
tc01_simple_race
tc02_simple_tls
tc03_re_excl
tc04_free_lock
tc05_simple_race
tc06_two_races
tc07_hbl1
tc08_hbl2
tc09_bad_unlock
tc10_rec_lock
tc11_XCHG
tc12_rwl_trivial
tc13_laog1
tc15_laog_lockdel
tc16_byterace
tc17_sembar
tc18_semabuse
tc19_shadowmem
tc20_verifywrap
tc21_pthonce
tc22_exit_w_lock
tc23_bogus_condwait
tc24_nonzero_sem
trylock
vg_regtest.tmp*
+ *.stderr.diff*
*.stderr.out
*.stdout.diff*
*.stdout.out
.deps
atomic_var
bar_bad
bar_trivial
boost_thread
circular_buffer
drd_bitmap_test
fp_race
hg01_all_ok
hg02_deadlock
hg03_inherit
hg04_race
hg05_race2
hg06_readshared
hold_lock
linuxthreads_det
Makefile
Makefile.in
matinv
memory_allocation
monitor_example
new_delete
omp_matinv
omp_prime
omp_printf
pth_barrier
pth_barrier_race
pth_barrier_reinit
pth_broadcast
pth_cancel_locked
pth_cond_race
pth_create_chain
pth_create_glibc_2_0
pth_detached
pth_detached_sem
pth_inconsistent_cond_wait
pth_mutex_reinit
pth_process_shared_mutex
pth_spinlock
qt4_mutex
qt4_rwlock
qt4_semaphore
recursive_mutex
rwlock_race
rwlock_test
sem_as_mutex
sigalrm
tc01_simple_race
tc02_simple_tls
tc03_re_excl
tc04_free_lock
tc05_simple_race
tc06_two_races
tc07_hbl1
tc08_hbl2
tc09_bad_unlock
tc10_rec_lock
tc11_XCHG
tc12_rwl_trivial
tc13_laog1
tc15_laog_lockdel
tc16_byterace
tc17_sembar
tc18_semabuse
tc19_shadowmem
tc20_verifywrap
tc21_pthonce
tc22_exit_w_lock
tc23_bogus_condwait
tc24_nonzero_sem
trylock
vg_regtest.tmp*
Modified: trunk/drd/tests/Makefile.am
===================================================================
--- trunk/drd/tests/Makefile.am 2009-05-16 06:22:46 UTC (rev 9851)
+++ trunk/drd/tests/Makefile.am 2009-05-16 06:24:40 UTC (rev 9852)
@@ -19,16 +19,16 @@
atomic_var.vgtest \
bar_bad.stderr.exp \
bar_bad.vgtest \
+ bar_trivial.stderr.exp \
bar_trivial.stdout.exp \
- bar_trivial.stderr.exp \
bar_trivial.vgtest \
boost_thread.stderr.exp \
boost_thread.vgtest \
circular_buffer.stderr.exp-with-atomic-builtins \
circular_buffer.stderr.exp-without-atomic-builtins \
circular_buffer.vgtest \
+ custom_alloc.stderr.exp \
custom_alloc.vgtest \
- custom_alloc.stderr.exp \
drd_bitmap_test.stderr.exp \
drd_bitmap_test.stdout.exp \
drd_bitmap_test.vgtest \
@@ -114,8 +114,10 @@
pth_inconsistent_cond_wait.stderr.exp1 \
pth_inconsistent_cond_wait.stderr.exp2 \
pth_inconsistent_cond_wait.vgtest \
+ pth_mutex_reinit.stderr.exp \
+ pth_mutex_reinit.vgtest \
+ pth_process_shared_mutex.c \
pth_process_shared_mutex.vgtest \
- pth_process_shared_mutex.c \
pth_spinlock.stderr.exp \
pth_spinlock.vgtest \
qt4_mutex.stderr.exp \
@@ -220,8 +222,9 @@
pth_create_chain \
pth_detached \
pth_detached_sem \
+ pth_inconsistent_cond_wait \
+ pth_mutex_reinit \
pth_process_shared_mutex \
- pth_inconsistent_cond_wait \
recursive_mutex \
rwlock_race \
rwlock_test \
Added: trunk/drd/tests/pth_mutex_reinit.c
===================================================================
--- trunk/drd/tests/pth_mutex_reinit.c (rev 0)
+++ trunk/drd/tests/pth_mutex_reinit.c 2009-05-16 06:24:40 UTC (rev 9852)
@@ -0,0 +1,36 @@
+/* Test program that triggers mutex reinitialization. */
+
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main(int argc, char** argv)
+{
+ pthread_mutex_t m;
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+ pthread_mutex_init(&m, &attr);
+ pthread_mutexattr_destroy(&attr);
+ pthread_mutex_lock(&m);
+ pthread_mutex_unlock(&m);
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&m, &attr);
+ pthread_mutexattr_destroy(&attr);
+ pthread_mutex_lock(&m);
+ pthread_mutex_unlock(&m);
+
+ pthread_mutex_destroy(&m);
+
+ fprintf(stderr, "Done.\n");
+
+ return 0;
+}
Added: trunk/drd/tests/pth_mutex_reinit.stderr.exp
===================================================================
--- trunk/drd/tests/pth_mutex_reinit.stderr.exp (rev 0)
+++ trunk/drd/tests/pth_mutex_reinit.stderr.exp 2009-05-16 06:24:40 UTC (rev 9852)
@@ -0,0 +1,10 @@
+
+Mutex reinitialization: mutex 0x........, recursion count 0, owner 1.
+ at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+ by 0x........: main (pth_mutex_reinit.c:?)
+mutex 0x........ was first observed at:
+ at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+ by 0x........: main (pth_mutex_reinit.c:?)
+Done.
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Added: trunk/drd/tests/pth_mutex_reinit.vgtest
===================================================================
--- trunk/drd/tests/pth_mutex_reinit.vgtest (rev 0)
+++ trunk/drd/tests/pth_mutex_reinit.vgtest 2009-05-16 06:24:40 UTC (rev 9852)
@@ -0,0 +1,3 @@
+prereq: test -e pth_mutex_reinit && ./supported_libpthread
+vgopts: --var-info=yes --check-stack-var=yes
+prog: pth_mutex_reinit
|
|
From: <sv...@va...> - 2009-05-16 06:22:55
|
Author: bart
Date: 2009-05-16 07:22:46 +0100 (Sat, 16 May 2009)
New Revision: 9851
Log:
Update mutex type upon mutex reinitialization such that DRD does not trigger an assertion failure when a reinitialized mutex is used.
Modified:
trunk/drd/drd_mutex.c
Modified: trunk/drd/drd_mutex.c
===================================================================
--- trunk/drd/drd_mutex.c 2009-05-16 02:07:55 UTC (rev 9850)
+++ trunk/drd/drd_mutex.c 2009-05-16 06:22:46 UTC (rev 9851)
@@ -193,6 +193,7 @@
VG_(get_IP)(vg_tid),
"Mutex reinitialization",
&MEI);
+ p->mutex_type = mutex_type;
return p;
}
p = DRD_(mutex_get_or_allocate)(mutex, mutex_type);
|
|
From: Tom H. <th...@cy...> - 2009-05-16 02:44:04
|
Nightly build on lloyd ( x86_64, Fedora 7 ) started at 2009-05-16 03:05:06 BST Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... done Regression test results follow == 480 tests, 0 stderr failures, 0 stdout failures, 0 post failures == |
|
From: Tom H. <th...@cy...> - 2009-05-16 02:27:51
|
Nightly build on mg ( x86_64, Fedora 9 ) started at 2009-05-16 03:10:04 BST Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 486 tests, 0 stderr failures, 1 stdout failure, 0 post failures == none/tests/linux/mremap2 (stdout) |
|
From: <sv...@va...> - 2009-05-16 02:08:42
|
Author: sewardj
Date: 2009-05-16 02:59:57 +0100 (Sat, 16 May 2009)
New Revision: 9848
Log:
* Reorganise: move routines into a somewhat more logical order,
and group
* Reimplement pp_Error: make it call pp_before_Error, generate
XML pre/post <error> tags, add a comment. Tidy up the callers
VG_(maybe_record_error) and VG_(unique_error) accordingly.
Modified:
branches/MESSAGING_TIDYUP/coregrind/m_errormgr.c
Modified: branches/MESSAGING_TIDYUP/coregrind/m_errormgr.c
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/m_errormgr.c 2009-05-16 01:55:20 UTC (rev 9847)
+++ branches/MESSAGING_TIDYUP/coregrind/m_errormgr.c 2009-05-16 01:59:57 UTC (rev 9848)
@@ -261,7 +261,8 @@
return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
}
-/* Compare errors, to detect duplicates. */
+/* Compare errors, to detect duplicates.
+*/
static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
{
if (e1->ekind != e2->ekind)
@@ -286,124 +287,10 @@
}
}
-/* This prints an error, either in text or XML mode. Note that in XML
- mode, it does not print the trailing </error> tag. That is so as
- to allow callers to print more stuff (specificially, an XML-form
- suppression for the error, by calling do_actions_on_error) before
- the closing tag. */
-static void pp_Error ( Error* err )
-{
- if (VG_(clo_xml)) {
- VG_(printf_xml)("<error>\n");
- VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
- VG_(printf_xml)(" <tid>%d</tid>\n", err->tid);
- }
- if (!VG_(clo_xml)) {
- if (VG_(tdict).tool_show_ThreadIDs_for_errors
- && err->tid > 0 && err->tid != last_tid_printed) {
- VG_(UMSG)("Thread %d:\n", err->tid );
- last_tid_printed = err->tid;
- }
- }
-
- switch (err->ekind) {
- //(example code, see comment on CoreSuppKind above)
- //case ThreadErr:
- // vg_assert(VG_(needs).core_errors);
- // VG_(tm_error_print)(err);
- // break;
- default:
- if (VG_(needs).tool_errors)
- VG_TDICT_CALL( tool_pp_Error, err );
- else {
- VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
- "probably needs to be set?\n",
- err->ekind);
- VG_(tool_panic)("unhandled error type");
- }
- }
-
- // No .. the caller must do this. See comment at the start of
- // this fn.
- //if (VG_(clo_xml))
- // VG_(printf_xml)("</error>\n");
-}
-
-/* Figure out if we want to perform a given action for this error, possibly
- by asking the user. */
-Bool VG_(is_action_requested) ( Char* action, Bool* clo )
-{
- Char ch, ch2;
- Int res;
-
- if (*clo == False)
- return False;
-
- VG_(UMSG)("\n");
-
- again:
- VG_(printf)(
- "==%d== "
- "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
- VG_(getpid)(), action
- );
-
- res = VG_(read)(VG_(clo_input_fd), &ch, 1);
- if (res != 1) goto ioerror;
- /* res == 1 */
- if (ch == '\n') return False;
- if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
- && ch != 'C' && ch != 'c') goto again;
-
- res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
- if (res != 1) goto ioerror;
- if (ch2 != '\n') goto again;
-
- /* No, don't want to do action. */
- if (ch == 'n' || ch == 'N') return False;
- /* Yes, want to do action. */
- if (ch == 'y' || ch == 'Y') return True;
- /* No, don't want to do action, and don't ask again either. */
- vg_assert(ch == 'c' || ch == 'C');
-
- ioerror:
- *clo = False;
- return False;
-}
-
-
-/* Construct an error */
-static __inline__
-void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
- Char* s, void* extra, ExeContext* where )
-{
- /* DO NOT MAKE unique_counter NON-STATIC */
- static UInt unique_counter = 0;
-
- tl_assert(tid < VG_N_THREADS);
-
- /* Core-only parts */
- err->unique = unique_counter++;
- err->next = NULL;
- err->supp = NULL;
- err->count = 1;
- err->tid = tid;
- if (NULL == where)
- err->where = VG_(record_ExeContext)( tid, 0 );
- else
- err->where = where;
-
- /* Tool-relevant parts */
- err->ekind = ekind;
- err->addr = a;
- err->extra = extra;
- err->string = s;
-
- /* sanity... */
- vg_assert( tid < VG_N_THREADS );
-}
-
+/* Helper function for suppression generation: print a single line of
+ a suppression pseudo-stack-trace, either in XML or text mode.
+*/
#define ERRTXT_LEN 4096
static void printSuppForIp(UInt n, Addr ip)
@@ -430,6 +317,9 @@
}
}
+
+/* Generate a suppression for an error, either in text or XML mode.
+*/
static void gen_suppression(Error* err)
{
ExeContext* ec = VG_(get_error_where)(err);
@@ -472,11 +362,70 @@
}
}
+
+/* Figure out if we want to perform a given action for this error,
+ possibly by asking the user.
+*/
+Bool VG_(is_action_requested) ( Char* action, Bool* clo )
+{
+ Char ch, ch2;
+ Int res;
+
+ /* First off, we shouldn't be asking the user anything if
+ we're in XML mode. */
+ if (VG_(clo_xml))
+ return False; /* That's a Nein, oder Nay as they say down here in B-W */
+
+ if (*clo == False)
+ return False;
+
+ VG_(UMSG)("\n");
+
+ again:
+ VG_(printf)(
+ "==%d== "
+ "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
+ VG_(getpid)(), action
+ );
+
+ res = VG_(read)(VG_(clo_input_fd), &ch, 1);
+ if (res != 1) goto ioerror;
+ /* res == 1 */
+ if (ch == '\n') return False;
+ if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
+ && ch != 'C' && ch != 'c') goto again;
+
+ res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
+ if (res != 1) goto ioerror;
+ if (ch2 != '\n') goto again;
+
+ /* No, don't want to do action. */
+ if (ch == 'n' || ch == 'N') return False;
+ /* Yes, want to do action. */
+ if (ch == 'y' || ch == 'Y') return True;
+ /* No, don't want to do action, and don't ask again either. */
+ vg_assert(ch == 'c' || ch == 'C');
+
+ ioerror:
+ *clo = False;
+ return False;
+}
+
+
+/* Do text-mode actions on error, that is, immediately after an error
+ is printed. These are:
+ * possibly, attach to a debugger
+ * possibly, generate a suppression.
+ Note this should not be called in XML mode!
+*/
static
void do_actions_on_error(Error* err, Bool allow_db_attach)
{
Bool still_noisy = True;
+ /* Should be assured by caller */
+ vg_assert( ! VG_(clo_xml) );
+
/* Perhaps we want a debugger attach at this point? */
if (allow_db_attach &&
VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_attach) ))
@@ -495,6 +444,119 @@
VG_(clo_gen_suppressions) = 0;
}
+
+/* Prints an error. Not entirely simple because of the differences
+ between XML and text mode output.
+
+ In XML mode:
+
+ * calls the tool's pre-show method, so the tool can create any
+ preamble ahead of the message, if it wants.
+
+ * prints the opening tag, and the <unique> and <tid> fields
+
+ * prints the tool-specific parts of the message
+
+ * if suppression generation is required, a suppression
+
+ * the closing tag
+
+ In text mode:
+
+ * calls the tool's pre-show method, so the tool can create any
+ preamble ahead of the message, if it wants.
+
+ * prints the tool-specific parts of the message
+
+ * calls do_actions_on_error. This optionally does a debugger
+ attach (and detach), and optionally prints a suppression; both
+ of these may require user input.
+*/
+static void pp_Error ( Error* err, Bool allow_db_attach )
+{
+ /* If this fails, you probably specified your tool's method
+ dictionary incorrectly. */
+ vg_assert(VG_(needs).tool_errors);
+
+ if (VG_(clo_xml)) {
+
+ /* Note, allow_db_attach is ignored in here. */
+
+ /* Ensure that suppression generation is either completely
+ enabled or completely disabled; either way, we won't require
+ any user input. m_main.process_cmd_line_options should
+ ensure the asserted condition holds. */
+ vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
+ || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
+
+ /* Pre-show it to the tool */
+ VG_TDICT_CALL( tool_before_pp_Error, err );
+
+ /* standard preamble */
+ VG_(printf_xml)("<error>\n");
+ VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
+ VG_(printf_xml)(" <tid>%d</tid>\n", err->tid);
+
+ /* actually print it */
+ VG_TDICT_CALL( tool_pp_Error, err );
+
+ if (VG_(clo_gen_suppressions) > 0)
+ gen_suppression(err);
+
+ /* postamble */
+ VG_(printf_xml)("</error>\n");
+
+ } else {
+
+ VG_TDICT_CALL( tool_before_pp_Error, err );
+
+ if (VG_(tdict).tool_show_ThreadIDs_for_errors
+ && err->tid > 0 && err->tid != last_tid_printed) {
+ VG_(UMSG)("Thread %d:\n", err->tid );
+ last_tid_printed = err->tid;
+ }
+
+ VG_TDICT_CALL( tool_pp_Error, err );
+
+ do_actions_on_error(err, allow_db_attach);
+
+ }
+}
+
+
+/* Construct an error */
+static
+void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
+ Char* s, void* extra, ExeContext* where )
+{
+ /* DO NOT MAKE unique_counter NON-STATIC */
+ static UInt unique_counter = 0;
+
+ tl_assert(tid < VG_N_THREADS);
+
+ /* Core-only parts */
+ err->unique = unique_counter++;
+ err->next = NULL;
+ err->supp = NULL;
+ err->count = 1;
+ err->tid = tid;
+ if (NULL == where)
+ err->where = VG_(record_ExeContext)( tid, 0 );
+ else
+ err->where = where;
+
+ /* Tool-relevant parts */
+ err->ekind = ekind;
+ err->addr = a;
+ err->extra = extra;
+ err->string = s;
+
+ /* sanity... */
+ vg_assert( tid < VG_N_THREADS );
+}
+
+
+
/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
just for pretty printing purposes. */
static Bool is_first_shown_context = True;
@@ -651,20 +713,19 @@
errors = p;
if (p->supp == NULL) {
n_errs_found++;
+ /* A bit of prettyprinting, to ensure there's a blank line
+ in between each error. */
if (!is_first_shown_context) {
if (VG_(clo_xml))
VG_(printf_xml)("\n");
else
VG_(UMSG)("\n");
}
- pp_Error(p);
+ /* Actually show the error; more complex than you might think. */
+ pp_Error( p, /*allow_db_attach*/True );
+ /* update stats */
is_first_shown_context = False;
n_errs_shown++;
- do_actions_on_error(p, /*allow_db_attach*/True);
- // Finish up the <error> block started by the call to pp_Error. See
- // comments on pp_Error for why pp_Error does not do this itself.
- if (VG_(clo_xml))
- VG_(printf_xml)("</error>\n");
} else {
n_errs_suppressed++;
p->supp->count++;
@@ -703,20 +764,19 @@
n_errs_found++;
if (print_error) {
+ /* A bit of prettyprinting, to ensure there's a blank line
+ in between each error. */
if (!is_first_shown_context) {
if (VG_(clo_xml))
VG_(printf_xml)("\n");
else
VG_(UMSG)("\n");
}
- pp_Error(&err);
+ /* Actually show the error; more complex than you might think. */
+ pp_Error(&err, allow_db_attach);
+ /* update stats */
is_first_shown_context = False;
n_errs_shown++;
- do_actions_on_error(&err, allow_db_attach);
- // Finish up the <error> block started by the call to pp_Error. See
- // comments on pp_Error for why pp_Error does not do this itself.
- if (VG_(clo_xml))
- VG_(printf_xml)("</error>\n");
}
return False;
@@ -822,10 +882,9 @@
VG_(UMSG)("\n");
VG_(UMSG)("%d errors in context %d of %d:\n",
p_min->count, i+1, n_err_contexts);
- pp_Error( p_min );
- // Finish up the <error> block started by the call to pp_Error. See
- // comments on pp_Error for why pp_Error does not do this itself.
- // Except, we're not printing XML -- we'd have exited above if so.
+ pp_Error( p_min, False/*allow_db_attach*/ );
+
+ // We're not printing XML -- we'd have exited above if so.
vg_assert(! VG_(clo_xml));
if ((i+1 == VG_(clo_dump_error))) {
|
|
From: <sv...@va...> - 2009-05-16 02:08:37
|
Author: sewardj
Date: 2009-05-16 02:42:30 +0100 (Sat, 16 May 2009)
New Revision: 9845
Log:
Change VG_(get_data_description):
* make it dump the text in an XArray* of HChar, hence allowing
the output to be arbitrarily long
* if VG_(clo_xml) is True, don't just generate human-readable
text, but also wrap the important parts up in separate tags,
using the AUXWHAT/XAUXWHAT scheme described in
docs/internals/xml-output-protocol4.txt
(will be committed shortly after this commit)
These changes are needed to support XML output of variable
type/location data derived from DWARF3, with --read-var-info=yes
(or for any tool which enables that by default).
Modified:
branches/MESSAGING_TIDYUP/coregrind/m_debuginfo/debuginfo.c
branches/MESSAGING_TIDYUP/include/pub_tool_debuginfo.h
Modified: branches/MESSAGING_TIDYUP/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/m_debuginfo/debuginfo.c 2009-05-16 01:35:13 UTC (rev 9844)
+++ branches/MESSAGING_TIDYUP/coregrind/m_debuginfo/debuginfo.c 2009-05-16 01:42:30 UTC (rev 9845)
@@ -2236,7 +2236,8 @@
spHere = *spP;
*ipP = *(Addr *)(spHere + 4*(fpo->cbRegs + fpo->cdwLocals));
- *spP = spHere + 4*(fpo->cbRegs + fpo->cdwLocals + 1 + fpo->cdwParams);
+ *spP = spHere + 4*(fpo->cbRegs + fpo->cdwLocals + 1
+ + fpo->cdwParams);
*fpP = *(Addr *)(spHere + 4*2);
return True;
}
@@ -2249,6 +2250,35 @@
/*--- ---*/
/*--------------------------------------------------------------*/
+/* Implement a "p2XA" function ("printf-to-XA"), which printfs into an
+ XArray of HChar, adding stuff at the end. This is very convenient
+ for concocting result strings in format_message(). Note that the
+ resulting string is NOT zero-terminated.
+
+ Unfortunately no format check on p2XA, since we need to use %t
+ for XML escaped-string output, and gcc complains about that.
+*/
+static void add_char_to_XA ( HChar c, void* opaque )
+{
+ XArray* dst = (XArray*)opaque;
+ (void) VG_(addBytesToXA)( dst, &c, 1 );
+}
+static void p2XA ( XArray* dst, const HChar* format, ... )
+{
+ va_list vargs;
+ va_start(vargs, format);
+ VG_(vcbprintf)( add_char_to_XA, (void*)dst, format, vargs );
+ va_end(vargs);
+}
+
+/* Add a zero-terminating byte to DST. */
+static void zterm_XA ( XArray* dst )
+{
+ HChar zero = 0;
+ (void) VG_(addBytesToXA)( dst, &zero, 1 );
+}
+
+
/* Evaluate the location expression/list for var, to see whether or
not data_addr falls within the variable. If so also return the
offset of data_addr from the start of the variable. Note that
@@ -2315,13 +2345,14 @@
}
-/* Format the acquired information into dname1[0 .. n_dname-1] and
- dname2[0 .. n_dname-1] in an understandable way. Not so easy.
- If frameNo is -1, this is assumed to be a global variable; else
- a local variable. */
-static void format_message ( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
+/* Format the acquired information into DN(AME)1 and DN(AME)2, which
+ are XArray*s of HChar, that have been initialised by the caller.
+ Resulting strings will be zero terminated. Information is
+ formatted in an understandable way. Not so easy. If frameNo is
+ -1, this is assumed to be a global variable; else a local
+ variable. */
+static void format_message ( /*MOD*/XArray* /* of HChar */ dn1,
+ /*MOD*/XArray* /* of HChar */ dn2,
Addr data_addr,
DiVariable* var,
PtrdiffT var_offset,
@@ -2330,20 +2361,36 @@
Int frameNo,
ThreadId tid )
{
- Bool have_descr, have_srcloc;
+ Bool have_descr, have_srcloc;
+ Bool xml = VG_(clo_xml);
UChar* vo_plural = var_offset == 1 ? "" : "s";
UChar* ro_plural = residual_offset == 1 ? "" : "s";
+ UChar* basetag = "auxwhat"; /* a constant */
+ UChar tagL[32], tagR[32], xagL[32], xagR[32];
vg_assert(frameNo >= -1);
- vg_assert(dname1 && dname2 && n_dname > 1);
+ vg_assert(dn1 && dn2);
vg_assert(described);
vg_assert(var && var->name);
have_descr = VG_(sizeXA)(described) > 0
&& *(UChar*)VG_(indexXA)(described,0) != '\0';
have_srcloc = var->fileName && var->lineNo > 0;
- dname1[0] = dname2[0] = '\0';
+ tagL[0] = tagR[0] = xagL[0] = xagR[0] = 0;
+ if (xml) {
+ VG_(sprintf)(tagL, "<%s>", basetag); // <auxwhat>
+ VG_(sprintf)(tagR, "</%s>", basetag); // </auxwhat>
+ VG_(sprintf)(xagL, "<x%s>", basetag); // <xauxwhat>
+ VG_(sprintf)(xagR, "</x%s>", basetag); // </xauxwhat>
+ }
+# define TAGL(_xa) p2XA(_xa, "%s", tagL)
+# define TAGR(_xa) p2XA(_xa, "%s", tagR)
+# define XAGL(_xa) p2XA(_xa, "%s", xagL)
+# define XAGR(_xa) p2XA(_xa, "%s", xagR)
+# define TXTL(_xa) p2XA(_xa, "%s", "<text>")
+# define TXTR(_xa) p2XA(_xa, "%s", "</text>")
+
/* ------ local cases ------ */
if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
@@ -2351,13 +2398,23 @@
Location 0x7fefff6cf is 543 bytes inside local var "a",
in frame #1 of thread 1
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside local var \"%s\",",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "in frame #%d of thread %d", frameNo, (Int)tid);
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside local var \"%t\",",
+ data_addr, var_offset, vo_plural, var->name );
+ TAGR( dn1 );
+ TAGL( dn2 );
+ p2XA( dn2,
+ "in frame #%d of thread %d", frameNo, (Int)tid );
+ TAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside local var \"%s\",",
+ data_addr, var_offset, vo_plural, var->name );
+ p2XA( dn2,
+ "in frame #%d of thread %d", frameNo, (Int)tid );
+ }
}
else
if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
@@ -2365,14 +2422,31 @@
Location 0x7fefff6cf is 543 bytes inside local var "a"
declared at dsyms7.c:17, in frame #1 of thread 1
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside local var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d, in frame #%d of thread %d",
- var->fileName, var->lineNo, frameNo, (Int)tid);
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside local var \"%t\"",
+ data_addr, var_offset, vo_plural, var->name );
+ TAGR( dn1 );
+ XAGL( dn2 );
+ TXTL( dn2 );
+ p2XA( dn2,
+ "declared at %t:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid );
+ TXTR( dn2 );
+ // FIXME: also do <dir>
+ p2XA( dn2,
+ " <file>%t</file> <line>%d</line> ",
+ var->fileName, var->lineNo );
+ XAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside local var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ p2XA( dn2,
+ "declared at %s:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid );
+ }
}
else
if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
@@ -2380,28 +2454,57 @@
Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
in frame #1 of thread 1
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside %s%s",
- data_addr, residual_offset, ro_plural, var->name,
- (char*)(VG_(indexXA)(described,0)) );
- VG_(snprintf)(
- dname2, n_dname,
- "in frame #%d of thread %d", frameNo, (Int)tid);
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %t%t",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ TAGR( dn1 );
+ TAGL( dn2 );
+ p2XA( dn2,
+ "in frame #%d of thread %d", frameNo, (Int)tid );
+ TAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %s%s",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ p2XA( dn2,
+ "in frame #%d of thread %d", frameNo, (Int)tid );
+ }
}
else
if ( frameNo >= 0 && have_srcloc && have_descr ) {
- /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
- declared at dsyms7.c:17, in frame #1 of thread 1 */
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- (char*)(VG_(indexXA)(described,0)) );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d, in frame #%d of thread %d",
- var->fileName, var->lineNo, frameNo, (Int)tid);
+ /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+ declared at dsyms7.c:17, in frame #1 of thread 1 */
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %t%t,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ TAGR( dn1 );
+ XAGL( dn2 );
+ TXTL( dn2 );
+ p2XA( dn2,
+ "declared at %t:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid );
+ TXTR( dn2 );
+ // FIXME: also do <dir>
+ p2XA( dn2,
+ " <file>%t</file> <line>%d</line> ",
+ var->fileName, var->lineNo );
+ XAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ p2XA( dn2,
+ "declared at %s:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid );
+ }
}
else
/* ------ global cases ------ */
@@ -2409,10 +2512,17 @@
/* no srcloc, no description:
Location 0x7fefff6cf is 543 bytes inside global var "a"
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside global var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside global var \"%t\"",
+ data_addr, var_offset, vo_plural, var->name );
+ TAGR( dn1 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside global var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ }
}
else
if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
@@ -2420,14 +2530,31 @@
Location 0x7fefff6cf is 543 bytes inside global var "a"
declared at dsyms7.c:17
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside global var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d",
- var->fileName, var->lineNo);
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside global var \"%t\"",
+ data_addr, var_offset, vo_plural, var->name );
+ TAGR( dn1 );
+ XAGL( dn2 );
+ TXTL( dn2 );
+ p2XA( dn2,
+ "declared at %t:%d",
+ var->fileName, var->lineNo);
+ TXTR( dn2 );
+ // FIXME: also do <dir>
+ p2XA( dn2,
+ " <file>%t</file> <line>%d</line> ",
+ var->fileName, var->lineNo );
+ XAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside global var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ p2XA( dn2,
+ "declared at %s:%d",
+ var->fileName, var->lineNo);
+ }
}
else
if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
@@ -2435,43 +2562,82 @@
Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
a global variable
*/
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- (char*)(VG_(indexXA)(described,0)) );
- VG_(snprintf)(
- dname2, n_dname,
- "a global variable");
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %t%t,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ TAGR( dn1 );
+ TAGL( dn2 );
+ p2XA( dn2,
+ "a global variable");
+ TAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (char*)(VG_(indexXA)(described,0)) );
+ p2XA( dn2,
+ "a global variable");
+ }
}
else
if ( frameNo >= -1 && have_srcloc && have_descr ) {
- /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
- a global variable declared at dsyms7.c:17 */
- VG_(snprintf)(
- dname1, n_dname,
- "Location 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- (char*)(VG_(indexXA)(described,0)) );
- VG_(snprintf)(
- dname2, n_dname,
- "a global variable declared at %s:%d",
- var->fileName, var->lineNo);
+ /* Location 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+ a global variable declared at dsyms7.c:17 */
+ if (xml) {
+ TAGL( dn1 );
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %t%t,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ TAGR( dn1 );
+ XAGL( dn2 );
+ TXTL( dn2 );
+ p2XA( dn2,
+ "a global variable declared at %t:%d",
+ var->fileName, var->lineNo);
+ TXTR( dn2 );
+ // FIXME: also do <dir>
+ p2XA( dn2,
+ " <file>%t</file> <line>%d</line> ",
+ var->fileName, var->lineNo );
+ XAGR( dn2 );
+ } else {
+ p2XA( dn1,
+ "Location 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ (HChar*)(VG_(indexXA)(described,0)) );
+ p2XA( dn2,
+ "a global variable declared at %s:%d",
+ var->fileName, var->lineNo);
+ }
}
else
vg_assert(0);
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ /* Zero terminate both strings */
+ zterm_XA( dn1 );
+ zterm_XA( dn2 );
+
+# undef TAGL
+# undef TAGR
+# undef XAGL
+# undef XAGR
+# undef TXTL
+# undef TXTR
}
+
/* Determine if data_addr is a local variable in the frame
- characterised by (ip,sp,fp), and if so write its description into
- dname{1,2}[0..n_dname-1], and return True. If not, return
- False. */
+ characterised by (ip,sp,fp), and if so write its description at the
+ ends of DNAME{1,2}, which are XArray*s of HChar, that have been
+ initialised by the caller, zero terminate both, and return True.
+ If it's not a local variable in said frame, return False. */
static
-Bool consider_vars_in_frame ( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
+Bool consider_vars_in_frame ( /*MOD*/XArray* /* of HChar */ dname1,
+ /*MOD*/XArray* /* of HChar */ dname2,
Addr data_addr,
Addr ip, Addr sp, Addr fp,
/* shown to user: */
@@ -2579,7 +2745,7 @@
XArray* described = ML_(describe_type)( &residual_offset,
di->admin_tyents,
var->typeR, offset );
- format_message( dname1, dname2, n_dname,
+ format_message( dname1, dname2,
data_addr, var, offset, residual_offset,
described, frameNo, tid );
VG_(deleteXA)( described );
@@ -2591,15 +2757,24 @@
return False;
}
-/* Try to form some description of data_addr by looking at the DWARF3
+/* Try to form some description of DATA_ADDR by looking at the DWARF3
debug info we have. This considers all global variables, and all
- frames in the stacks of all threads. Result (or as much as will
- fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
- to be zero terminated. */
-Bool VG_(get_data_description)( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
- Addr data_addr )
+ frames in the stacks of all threads. Result is written at the ends
+ of DNAME{1,2}V, which are XArray*s of HChar, that have been
+ initialised by the caller, and True is returned. If no description
+ is created, False is returned. Regardless of the return value,
+ DNAME{1,2}V are guaranteed to be zero terminated after the call.
+
+ Note that after the call, DNAME{1,2} may have more than one
+ trailing zero, so callers should establish the useful text length
+ using VG_(strlen) on the contents, rather than VG_(sizeXA) on the
+ XArray itself.
+*/
+Bool VG_(get_data_description)(
+ /*MOD*/ void* /* really, XArray* of HChar */ dname1v,
+ /*MOD*/ void* /* really, XArray* of HChar */ dname2v,
+ Addr data_addr
+ )
{
# define N_FRAMES 8
Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
@@ -2611,8 +2786,8 @@
DebugInfo* di;
Word j;
- vg_assert(n_dname > 1);
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ XArray* dname1 = (XArray*)dname1v;
+ XArray* dname2 = (XArray*)dname2v;
if (0) VG_(printf)("get_data_description: dataaddr %#lx\n", data_addr);
/* First, see if data_addr is (or is part of) a global variable.
@@ -2678,11 +2853,12 @@
XArray* described = ML_(describe_type)( &residual_offset,
di->admin_tyents,
var->typeR, offset );
- format_message( dname1, dname2, n_dname,
+ format_message( dname1, dname2,
data_addr, var, offset, residual_offset,
described, -1/*frameNo*/, tid );
VG_(deleteXA)( described );
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return True;
}
}
@@ -2702,12 +2878,13 @@
while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
if (stack_min >= stack_max)
continue; /* ignore obviously stupid cases */
- if (consider_vars_in_frame( dname1, dname2, n_dname,
+ if (consider_vars_in_frame( dname1, dname2,
data_addr,
VG_(get_IP)(tid),
VG_(get_SP)(tid),
VG_(get_FP)(tid), tid, 0 )) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return True;
}
}
@@ -2726,7 +2903,8 @@
}
}
if (!found) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return False;
}
@@ -2741,11 +2919,12 @@
Oh well. */
vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
for (j = 0; j < n_frames; j++) {
- if (consider_vars_in_frame( dname1, dname2, n_dname,
+ if (consider_vars_in_frame( dname1, dname2,
data_addr,
ips[j],
sps[j], fps[j], tid, j )) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return True;
}
/* Now, it appears that gcc sometimes appears to produce
@@ -2767,17 +2946,19 @@
either (1) I misunderstood something, or (2) GDB has an
equivalent kludge. */
if (j > 0 /* this is a non-innermost frame */
- && consider_vars_in_frame( dname1, dname2, n_dname,
+ && consider_vars_in_frame( dname1, dname2,
data_addr,
ips[j] + 1,
sps[j], fps[j], tid, j )) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return True;
}
}
/* We didn't find anything useful. */
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ zterm_XA( dname1 );
+ zterm_XA( dname2 );
return False;
# undef N_FRAMES
}
Modified: branches/MESSAGING_TIDYUP/include/pub_tool_debuginfo.h
===================================================================
--- branches/MESSAGING_TIDYUP/include/pub_tool_debuginfo.h 2009-05-16 01:35:13 UTC (rev 9844)
+++ branches/MESSAGING_TIDYUP/include/pub_tool_debuginfo.h 2009-05-16 01:42:30 UTC (rev 9845)
@@ -95,16 +95,25 @@
/*OUT*/Char* dname, Int n_dname,
/*OUT*/PtrdiffT* offset );
-/* Try to form some description of data_addr by looking at the DWARF3
+/* Try to form some description of DATA_ADDR by looking at the DWARF3
debug info we have. This considers all global variables, and all
- frames in the stacks of all threads. Result (or as much as will
- fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
- to be zero terminated. */
-extern Bool VG_(get_data_description)( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
- Addr data_addr );
+ frames in the stacks of all threads. Result is written at the ends
+ of DNAME{1,2}V, which are XArray*s of HChar, that have been
+ initialised by the caller, and True is returned. If no description
+ is created, False is returned. Regardless of the return value,
+ DNAME{1,2}V are guaranteed to be zero terminated after the call.
+ Note that after the call, DNAME{1,2} may have more than one
+ trailing zero, so callers should establish the useful text length
+ using VG_(strlen) on the contents, rather than VG_(sizeXA) on the
+ XArray itself.
+*/
+Bool VG_(get_data_description)(
+ /*MOD*/ void* /* really, XArray* of HChar */ dname1v,
+ /*MOD*/ void* /* really, XArray* of HChar */ dname2v,
+ Addr data_addr
+ );
+
/* Succeeds if the address is within a shared object or the main executable.
It doesn't matter if debug info is present or not. */
extern Bool VG_(get_objname) ( Addr a, Char* objname, Int n_objname );
|
|
From: <sv...@va...> - 2009-05-16 02:08:10
|
Author: sewardj
Date: 2009-05-16 03:07:55 +0100 (Sat, 16 May 2009)
New Revision: 9850
Log:
Update XML output to sync with Protocol 4 revisions that were
committed in r9849.
Modified:
branches/MESSAGING_TIDYUP/helgrind/hg_errors.c
Modified: branches/MESSAGING_TIDYUP/helgrind/hg_errors.c
===================================================================
--- branches/MESSAGING_TIDYUP/helgrind/hg_errors.c 2009-05-16 02:05:19 UTC (rev 9849)
+++ branches/MESSAGING_TIDYUP/helgrind/hg_errors.c 2009-05-16 02:07:55 UTC (rev 9850)
@@ -183,8 +183,8 @@
Thread* mb_confaccthr;
Int mb_confaccSzB;
Bool mb_confaccIsW;
- Char descr1[96];
- Char descr2[96];
+ XArray* descr1; /* XArray* of HChar */
+ XArray* descr2; /* XArray* of HChar */
} Race;
struct {
Thread* thr; /* doing the unlocking */
@@ -251,6 +251,7 @@
//}
if (xe->tag == XE_Race) {
+
/* See if we can come up with a source level description of the
raced-upon address. This is potentially expensive, which is
why it's only done at the update_extra point, not when the
@@ -260,17 +261,38 @@
if (0)
VG_(printf)("HG_(update_extra): "
"%d conflicting-event queries\n", xxx);
- tl_assert(sizeof(xe->XE.Race.descr1) == sizeof(xe->XE.Race.descr2));
- if (VG_(get_data_description)(
- &xe->XE.Race.descr1[0],
- &xe->XE.Race.descr2[0],
- sizeof(xe->XE.Race.descr1)-1,
- xe->XE.Race.data_addr )) {
- tl_assert( xe->XE.Race.descr1
- [ sizeof(xe->XE.Race.descr1)-1 ] == 0);
- tl_assert( xe->XE.Race.descr2
- [ sizeof(xe->XE.Race.descr2)-1 ] == 0);
+ tl_assert(!xe->XE.Race.descr1);
+ tl_assert(!xe->XE.Race.descr2);
+
+ xe->XE.Race.descr1
+ = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr1",
+ HG_(free), sizeof(HChar) );
+ xe->XE.Race.descr2
+ = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr2",
+ HG_(free), sizeof(HChar) );
+
+ (void) VG_(get_data_description)( xe->XE.Race.descr1,
+ xe->XE.Race.descr2,
+ xe->XE.Race.data_addr );
+
+ /* If there's nothing in descr1/2, free it. Why is it safe to
+ to VG_(indexXA) at zero here? Because
+ VG_(get_data_description) guarantees to zero terminate
+ descr1/2 regardless of the outcome of the call. So there's
+ always at least one element in each XA after the call.
+ */
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Race.descr1, 0 ))) {
+ VG_(deleteXA)( xe->XE.Race.descr1 );
+ xe->XE.Race.descr1 = NULL;
}
+ if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Race.descr2, 0 ))) {
+ VG_(deleteXA)( xe->XE.Race.descr2 );
+ xe->XE.Race.descr2 = NULL;
+ }
+
+ /* And poke around in the conflicting-event map, to see if we
+ can rustle up a plausible-looking conflicting memory access
+ to show. */
{ Thr* thrp = NULL;
ExeContext* wherep = NULL;
Addr acc_addr = xe->XE.Race.data_addr;
@@ -333,7 +355,11 @@
xe.XE.Race.thr = thr;
tl_assert(isWrite == False || isWrite == True);
tl_assert(szB == 8 || szB == 4 || szB == 2 || szB == 1);
- xe.XE.Race.descr1[0] = xe.XE.Race.descr2[0] = 0;
+ /* 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. */
+ tl_assert(xe.XE.Race.descr1 == NULL);
+ tl_assert(xe.XE.Race.descr2 == NULL);
// 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
@@ -540,167 +566,320 @@
/* Announce (that is, print the point-of-creation) of 'thr'. Only do
this once, as we only want to see these announcements once per
- thread. For the moment, don't do this in XML mode, as there is no
- provision for representing the result in XML Protocol 4 output.
+ thread. Returned Bool indicates whether or not an announcement was
+ made.
*/
-static void announce_one_thread ( Thread* thr )
+static Bool announce_one_thread ( Thread* thr )
{
tl_assert(HG_(is_sane_Thread)(thr));
tl_assert(thr->errmsg_index >= 1);
- if (VG_(clo_xml))
- return;
- if (!thr->announced) {
+ if (thr->announced)
+ return False;
+
+ if (VG_(clo_xml)) {
+
+ VG_(printf_xml)("<announcethread>\n");
+ VG_(printf_xml)(" <hthreadid>%d</threadid>\n", thr->errmsg_index);
if (thr->errmsg_index == 1) {
tl_assert(thr->created_at == NULL);
- VG_(message)(Vg_UserMsg, "Thread #%d is the program's root thread\n",
- thr->errmsg_index);
+ VG_(printf_xml)(" <isrootthread></isrootthread>\n");
} else {
tl_assert(thr->created_at != NULL);
+ VG_(pp_ExeContext)( thr->created_at );
+ }
+ VG_(printf_xml)("</announcethread>\n\n");
+
+ } else {
+
+ if (thr->errmsg_index == 1) {
+ tl_assert(thr->created_at == NULL);
+ VG_(message)(Vg_UserMsg,
+ "Thread #%d is the program's root thread\n",
+ thr->errmsg_index);
+ } else {
+ tl_assert(thr->created_at != NULL);
VG_(message)(Vg_UserMsg, "Thread #%d was created\n",
thr->errmsg_index);
VG_(pp_ExeContext)( thr->created_at );
}
VG_(message)(Vg_UserMsg, "\n");
- thr->announced = True;
+
}
+
+ thr->announced = True;
+ return True;
}
+/* This is the "this error is due to be printed shortly; so have a
+ look at it any print any preamble you want" function. We use it to
+ announce any previously un-announced threads in the upcoming error
+ message.
+*/
+void HG_(before_pp_Error) ( Error* err )
+{
+ XError* xe;
+ tl_assert(err);
+ xe = (XError*)VG_(get_error_extra)(err);
+ tl_assert(xe);
+
+ switch (VG_(get_error_kind)(err)) {
+ case XE_Misc:
+ announce_one_thread( xe->XE.Misc.thr );
+ break;
+ case XE_LockOrder:
+ announce_one_thread( xe->XE.LockOrder.thr );
+ break;
+ case XE_PthAPIerror:
+ announce_one_thread( xe->XE.PthAPIerror.thr );
+ break;
+ case XE_UnlockBogus:
+ announce_one_thread( xe->XE.UnlockBogus.thr );
+ break;
+ case XE_UnlockForeign:
+ announce_one_thread( xe->XE.UnlockForeign.thr );
+ announce_one_thread( xe->XE.UnlockForeign.owner );
+ break;
+ case XE_UnlockUnlocked:
+ announce_one_thread( xe->XE.UnlockUnlocked.thr );
+ break;
+ case XE_Race:
+ announce_one_thread( xe->XE.Race.thr );
+ if (xe->XE.Race.mb_confaccthr)
+ announce_one_thread( xe->XE.Race.mb_confaccthr );
+ break;
+ default:
+ tl_assert(0);
+ }
+}
+
+
void HG_(pp_Error) ( Error* err )
{
- HChar* what_pre0 = VG_(clo_xml) ? " <what>" : "";
- HChar* what_pre3 = VG_(clo_xml) ? " <what>" : " ";
- HChar* what_post = VG_(clo_xml) ? "</what>" : "";
- HChar* auxw_pre1 = VG_(clo_xml) ? " <auxwhat>" : " ";
- HChar* auxw_pre2 = VG_(clo_xml) ? " <auxwhat>" : " ";
- HChar* auxw_post = VG_(clo_xml) ? "</auxwhat>" : "";
+ const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
XError *xe = (XError*)VG_(get_error_extra)(err);
+ tl_assert(xe);
switch (VG_(get_error_kind)(err)) {
case XE_Misc: {
- tl_assert(xe);
tl_assert( HG_(is_sane_Thread)( xe->XE.Misc.thr ) );
- announce_one_thread( xe->XE.Misc.thr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>Misc</kind>\n");
- emit( "%sThread #%d: %s%s\n",
- what_pre0,
- (Int)xe->XE.Misc.thr->errmsg_index,
- xe->XE.Misc.errstr,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (xml) {
+
+ emit( " <kind>Misc</kind>\n");
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d: %s</text>\n",
+ (Int)xe->XE.Misc.thr->errmsg_index,
+ xe->XE.Misc.errstr );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.Misc.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ } else {
+
+ emit( "Thread #%d: %s\n",
+ (Int)xe->XE.Misc.thr->errmsg_index,
+ xe->XE.Misc.errstr );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ }
break;
}
case XE_LockOrder: {
- tl_assert(xe);
tl_assert( HG_(is_sane_Thread)( xe->XE.LockOrder.thr ) );
- announce_one_thread( xe->XE.LockOrder.thr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>LockOrder</kind>\n");
- emit( "%sThread #%d: lock order \"%p before %p\" violated%s\n",
- what_pre0,
- (Int)xe->XE.LockOrder.thr->errmsg_index,
- (void*)xe->XE.LockOrder.before_ga,
- (void*)xe->XE.LockOrder.after_ga,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) {
- emit(
- "%sRequired order was established by acquisition of lock at %p%s\n",
- auxw_pre2, (void*)xe->XE.LockOrder.before_ga, auxw_post
- );
- VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec );
- emit(
- "%sfollowed by a later acquisition of lock at %p%s\n",
- auxw_pre2, (void*)xe->XE.LockOrder.after_ga, auxw_post
- );
- VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec );
+
+ if (xml) {
+
+ emit( " <kind>LockOrder</kind>\n");
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d: lock order \"%p before %p\" "
+ "violated</text>\n",
+ (Int)xe->XE.LockOrder.thr->errmsg_index,
+ (void*)xe->XE.LockOrder.before_ga,
+ (void*)xe->XE.LockOrder.after_ga );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.LockOrder.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) {
+ emit( " <auxwhat>Required order was established by "
+ "acquisition of lock at %p</auxwhat>\n",
+ (void*)xe->XE.LockOrder.before_ga );
+ VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec );
+ emit( " <auxwhat>followed by a later acquisition "
+ "of lock at %p</auxwhat>\n",
+ (void*)xe->XE.LockOrder.after_ga );
+ VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec );
+ }
+
+ } else {
+
+ emit( "Thread #%d: lock order \"%p before %p\" violated\n",
+ (Int)xe->XE.LockOrder.thr->errmsg_index,
+ (void*)xe->XE.LockOrder.before_ga,
+ (void*)xe->XE.LockOrder.after_ga );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) {
+ emit( " Required order was established by "
+ "acquisition of lock at %p\n",
+ (void*)xe->XE.LockOrder.before_ga );
+ VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec );
+ emit( " followed by a later acquisition of lock at %p\n",
+ (void*)xe->XE.LockOrder.after_ga );
+ VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec );
+ }
+
}
+
break;
}
case XE_PthAPIerror: {
- tl_assert(xe);
tl_assert( HG_(is_sane_Thread)( xe->XE.PthAPIerror.thr ) );
- announce_one_thread( xe->XE.PthAPIerror.thr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>PthAPIerror</kind>\n");
- emit_no_f_c( "%sThread #%d's call to %t failed%s\n",
- what_pre0, (Int)xe->XE.PthAPIerror.thr->errmsg_index,
- xe->XE.PthAPIerror.fnname, what_post );
- emit( "%swith error code %ld (%s)%s\n",
- what_pre3,
- xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (xml) {
+
+ emit( " <kind>PthAPIerror</kind>\n");
+ emit( " <xwhat>\n" );
+ emit_no_f_c(
+ " <text>Thread #%d's call to %t failed</text>\n",
+ (Int)xe->XE.PthAPIerror.thr->errmsg_index,
+ xe->XE.PthAPIerror.fnname );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.PthAPIerror.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ emit( " <what>with error code %ld (%s)</what>\n",
+ xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ } else {
+
+ emit_no_f_c( "Thread #%d's call to %t failed\n",
+ (Int)xe->XE.PthAPIerror.thr->errmsg_index,
+ xe->XE.PthAPIerror.fnname );
+ emit( " with error code %ld (%s)\n",
+ xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ }
+
break;
}
case XE_UnlockBogus: {
- tl_assert(xe);
tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockBogus.thr ) );
- announce_one_thread( xe->XE.UnlockBogus.thr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>UnlockBogus</kind>\n");
- emit( "%sThread #%d unlocked an invalid lock at %p %s\n",
- what_pre0,
- (Int)xe->XE.UnlockBogus.thr->errmsg_index,
- (void*)xe->XE.UnlockBogus.lock_ga,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (xml) {
+
+ emit( " <kind>UnlockBogus</kind>\n");
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d unlocked an invalid "
+ "lock at %p</text>\n",
+ (Int)xe->XE.UnlockBogus.thr->errmsg_index,
+ (void*)xe->XE.UnlockBogus.lock_ga );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.UnlockBogus.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ } else {
+
+ emit( "Thread #%d unlocked an invalid lock at %p\n",
+ (Int)xe->XE.UnlockBogus.thr->errmsg_index,
+ (void*)xe->XE.UnlockBogus.lock_ga );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ }
+
break;
}
case XE_UnlockForeign: {
- tl_assert(xe);
tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockForeign.lock ) );
tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.owner ) );
tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.thr ) );
- announce_one_thread( xe->XE.UnlockForeign.thr );
- announce_one_thread( xe->XE.UnlockForeign.owner );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>UnlockForeign</kind>\n");
- emit( "%sThread #%d unlocked lock at %p "
- "currently held by thread #%d%s\n",
- what_pre0,
- (Int)xe->XE.UnlockForeign.thr->errmsg_index,
- (void*)xe->XE.UnlockForeign.lock->guestaddr,
- (Int)xe->XE.UnlockForeign.owner->errmsg_index,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- if (xe->XE.UnlockForeign.lock->appeared_at) {
- emit( "%sLock at %p was first observed%s\n",
- auxw_pre2,
+
+ if (xml) {
+
+ emit( " <kind>UnlockForeign</kind>\n");
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d unlocked lock at %p "
+ "currently held by thread #%d</text>\n",
+ (Int)xe->XE.UnlockForeign.thr->errmsg_index,
(void*)xe->XE.UnlockForeign.lock->guestaddr,
- auxw_post );
- VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
+ (Int)xe->XE.UnlockForeign.owner->errmsg_index );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.UnlockForeign.thr->errmsg_index );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.UnlockForeign.owner->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (xe->XE.UnlockForeign.lock->appeared_at) {
+ emit( " <auxwhat>Lock at %p was first observed</auxwhat>\n",
+ (void*)xe->XE.UnlockForeign.lock->guestaddr );
+ VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
+ }
+
+ } else {
+
+ emit( "Thread #%d unlocked lock at %p "
+ "currently held by thread #%d\n",
+ (Int)xe->XE.UnlockForeign.thr->errmsg_index,
+ (void*)xe->XE.UnlockForeign.lock->guestaddr,
+ (Int)xe->XE.UnlockForeign.owner->errmsg_index );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.UnlockForeign.lock->appeared_at) {
+ emit( " Lock at %p was first observed\n",
+ (void*)xe->XE.UnlockForeign.lock->guestaddr );
+ VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
+ }
+
}
+
break;
}
case XE_UnlockUnlocked: {
- tl_assert(xe);
tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockUnlocked.lock ) );
tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockUnlocked.thr ) );
- announce_one_thread( xe->XE.UnlockUnlocked.thr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>UnlockUnlocked</kind>\n");
- emit( "%sThread #%d unlocked a not-locked lock at %p %s\n",
- what_pre0,
- (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
- (void*)xe->XE.UnlockUnlocked.lock->guestaddr,
- what_post );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- if (xe->XE.UnlockUnlocked.lock->appeared_at) {
- emit( "%sLock at %p was first observed%s\n",
- auxw_pre2,
- (void*)xe->XE.UnlockUnlocked.lock->guestaddr,
- auxw_post );
- VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
+
+ if (xml) {
+
+ emit( " <kind>UnlockUnlocked</kind>\n");
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d unlocked a "
+ "not-locked lock at %p</text>\n",
+ (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
+ (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.UnlockUnlocked.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.UnlockUnlocked.lock->appeared_at) {
+ emit( " <auxwhat>Lock at %p was first observed</auxwhat>\n",
+ (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
+ VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
+ }
+
+ } else {
+
+ emit( "Thread #%d unlocked a not-locked lock at %p\n",
+ (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
+ (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.UnlockUnlocked.lock->appeared_at) {
+ emit( " Lock at %p was first observed\n",
+ (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
+ VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
+ }
+
}
+
break;
}
@@ -712,49 +891,79 @@
szB = xe->XE.Race.szB;
err_ga = VG_(get_error_address)(err);
- announce_one_thread( xe->XE.Race.thr );
+ tl_assert( HG_(is_sane_Thread)( xe->XE.Race.thr ));
if (xe->XE.Race.mb_confaccthr)
- announce_one_thread( xe->XE.Race.mb_confaccthr );
- if (VG_(clo_xml))
- VG_(printf_xml)( " <kind>Race</kind>\n");
- emit(
- "%sPossible data race during %s of size %d "
- "at %#lx by thread #%d%s\n",
- what_pre0, what, szB, err_ga,
- (Int)xe->XE.Race.thr->errmsg_index, what_post
- );
- VG_(pp_ExeContext)( VG_(get_error_where)(err) );
- if (xe->XE.Race.mb_confacc) {
- if (xe->XE.Race.mb_confaccthr) {
- emit(
- "%sThis conflicts with a previous %s of size %d "
- "by thread #%d%s\n",
- auxw_pre1,
- xe->XE.Race.mb_confaccIsW ? "write" : "read",
- xe->XE.Race.mb_confaccSzB,
- xe->XE.Race.mb_confaccthr->errmsg_index,
- auxw_post
- );
- } else {
- // FIXME: can this ever happen?
- emit(
- "%sThis conflicts with a previous %s of size %d%s\n",
- auxw_pre1,
- xe->XE.Race.mb_confaccIsW ? "write" : "read",
- xe->XE.Race.mb_confaccSzB,
- auxw_post
- );
+ tl_assert( HG_(is_sane_Thread)( xe->XE.Race.mb_confaccthr ));
+
+ if (xml) {
+
+ /* ------ XML ------ */
+ emit( " <kind>Race</kind>\n" );
+ emit( " <xwhat>\n" );
+ emit( " <text>Possible data race during %s of size %d "
+ "at %#lx by thread #%d</text>\n",
+ what, szB, err_ga, (Int)xe->XE.Race.thr->errmsg_index );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.Race.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+
+ if (xe->XE.Race.mb_confacc) {
+ if (xe->XE.Race.mb_confaccthr) {
+ emit( " <xauxwhat>\n");
+ emit( " <text>This conflicts with a previous %s of size %d "
+ "by thread #%d</text>\n",
+ xe->XE.Race.mb_confaccIsW ? "write" : "read",
+ xe->XE.Race.mb_confaccSzB,
+ xe->XE.Race.mb_confaccthr->errmsg_index );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ xe->XE.Race.mb_confaccthr->errmsg_index);
+ emit(" </xauxwhat>\n");
+ } else {
+ // FIXME: can this ever happen?
+ emit( " <auxwhat>This conflicts with a previous %s "
+ "of size %d</auxwhat>\n",
+ xe->XE.Race.mb_confaccIsW ? "write" : "read",
+ xe->XE.Race.mb_confaccSzB );
+ }
+ VG_(pp_ExeContext)( xe->XE.Race.mb_confacc );
}
- VG_(pp_ExeContext)( xe->XE.Race.mb_confacc );
+
+ } else {
+
+ /* ------ Text ------ */
+ emit( "Possible data race during %s of size %d "
+ "at %#lx by thread #%d\n",
+ what, szB, err_ga, (Int)xe->XE.Race.thr->errmsg_index );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.Race.mb_confacc) {
+ if (xe->XE.Race.mb_confaccthr) {
+ emit( " This conflicts with a previous %s of size %d "
+ "by thread #%d\n",
+ xe->XE.Race.mb_confaccIsW ? "write" : "read",
+ xe->XE.Race.mb_confaccSzB,
+ xe->XE.Race.mb_confaccthr->errmsg_index );
+ } else {
+ // FIXME: can this ever happen?
+ emit( " This conflicts with a previous %s of size %d\n",
+ xe->XE.Race.mb_confaccIsW ? "write" : "read",
+ xe->XE.Race.mb_confaccSzB );
+ }
+ VG_(pp_ExeContext)( xe->XE.Race.mb_confacc );
+ }
+
}
- /* If we have a better description of the address, show it. */
- if (xe->XE.Race.descr1[0] != 0)
- emit_no_f_c( "%s%t%s\n",
- auxw_pre1, &xe->XE.Race.descr1[0], auxw_post );
- if (xe->XE.Race.descr2[0] != 0)
- emit_no_f_c( "%s%t%s\n",
- auxw_pre1, &xe->XE.Race.descr2[0], auxw_post );
+ /* 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 (xe->XE.Race.descr1)
+ emit( "%s%s\n", xml ? " " : " ",
+ (HChar*)VG_(indexXA)( xe->XE.Race.descr1, 0 ) );
+ if (xe->XE.Race.descr2)
+ emit( "%s%s\n", xml ? " " : " ",
+ (HChar*)VG_(indexXA)( xe->XE.Race.descr2, 0 ) );
break; /* case XE_Race */
} /* case XE_Race */
|
|
From: <sv...@va...> - 2009-05-16 02:05:34
|
Author: sewardj
Date: 2009-05-16 03:05:19 +0100 (Sat, 16 May 2009)
New Revision: 9849
Log:
Significantly overhaul XML format so as to be able to handle
Helgrind's output properly. Memcheck/Ptrcheck are still TODO.
Modified:
branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt
Modified: branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt
===================================================================
--- branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt 2009-05-16 01:59:57 UTC (rev 9848)
+++ branches/MESSAGING_TIDYUP/docs/internals/xml-output-protocol4.txt 2009-05-16 02:05:19 UTC (rev 9849)
@@ -31,6 +31,18 @@
with the protocol number, for easy determination of parseability.
+How this specification is structured
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The TOPLEVEL nonterminal specifies top level XML output structure. It
+is common to all error producing tools.
+
+TOPLEVEL references TOOLSPECIFICs for each tool, and these are defined
+differently for each tool. Each TOOLSPECIFIC is an error, which is
+tool-specific. For Helgrind, a TOOLSPECIFIC may also contain a
+so-called thread-announcement record (described below).
+
+
Protocol 4 changes for Memcheck
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -159,7 +171,7 @@
human-understandable. In current Valgrind versions it is the
elapsed wallclock time since process start.
-* Zero or more of (either ERROR or ERRORCOUNTS).
+* Zero or more of (either ERRORCOUNTS or TOOLSPECIFIC).
* The following, indicating that the program has now finished, and
that the any final wrapup (eg, for Memcheck, leak checking) is happening.
@@ -168,17 +180,17 @@
<time>human-readable-time-string</time>
</status>
-* Zero or more of (either ERROR or ERRORCOUNTS). In Memcheck's case
- these will be complaints from the leak checker. For Ptrcheck and
- Helgrind we don't expect any output here (but the spec does not
+* Zero or more of (either ERRORCOUNTS or TOOLSPECIFIC). In Memcheck's
+ case these will be complaints from the leak checker. For Ptrcheck
+ and Helgrind we don't expect any output here (but the spec does not
guarantee that either).
* SUPPCOUNTS, indicating how many times each suppression was used.
-That's it. The tool-specific definitions for ERROR are below; however
-let's first continue with some smaller nonterminals used in the
-construction of errors for all the tool types.
+That's it. The tool-specific definitions for TOOLSPECIFIC are below;
+however let's first continue with some smaller nonterminals used in
+the construction of errors for all the tool types.
====================================================================
@@ -289,20 +301,78 @@
eg denoting "fun:*libc_write"
+WHAT and XWHAT
+--------------
+
+WHAT supplies a single line of text, which is a human-understandable,
+primary description of an error.
+
+XWHAT is an extended version of WHAT. It also contains a piece
+of text intended for human reading, but in addition may contain
+arbitrary other tagged data. This extra data is tool-specific, and
+is intended to supply GUIs with links to other data in the
+sequence of TOOLSPECIFICs, that are associated with the error.
+
+For example, we could get:
+
+ <what>Possible data race on address 0x12345678</what>
+
+or alternatively
+
+ <xwhat>
+ <text>Possible data race by thread #17 on address 0x12345678</text>
+ <threadid>17</threadid>
+ </xwhat>
+
+And presumably the <threadid>17</threadid> refers to some previously
+emitted entity in the stream of TOOLSPECIFICs for this tool.
+
+In an XWHAT, the <text> tag-pair is mandatory. GUIs which don't want
+to handle the extra fields can just ignore them and display the text
+part. In this way they have the option to present at least something
+useful to the user even in the case where the extra fields can't be
+handled, for whatever reason.
+
+A corollary of this is that the degenerate extended case
+
+ <xwhat> <text>T</text> </xwhat>
+
+is exactly equivalent to
+
+ <what>T</what>
+
+
+AUXWHAT and XAUXWHAT
+--------------------
+
+AUXWHAT is exactly like WHAT: a single line of text. It provides
+additional, secondary description of an error, that should be shown to
+the user.
+
+XAUXWHAT relates to AUXWHAT in the same way XWHAT relates to WHAT: it
+wraps up extra tagged info along with the line of text that would be
+in the AUXWHAT.
+
+
====================================================================
-ERROR definition -- common fields
----------------------------------
+ERROR definition -- common structure
+------------------------------------
ERROR defines an error, and is the most complex nonterminal. For all
-of the tools, the first four fields and the last field are common:
+of the tools, the structure is mostly common, and always conforms to
+the following:
<error>
<unique>HEX64</unique>
<tid>INT</tid>
<kind>KIND</kind>
- <what>TEXT</what> (either 1 or 2 times)
+ (either WHAT or XWHAT)
+ optionally: (either WHAT or XWHAT)
+
+ STACK
+
... tool-specific fields ...
optionally: SUPPRESSION
@@ -310,7 +380,7 @@
* Each error contains a unique, arbitrary 64-bit hex number. This is
- used to refer to the error in ERRORCOUNTS nonterminals (see below).
+ used to refer to the error in ERRORCOUNTS nonterminals (see above).
* The <tid> tag indicates the Valgrind thread number. This value
is arbitrary but may be used to determine which threads produced
@@ -321,15 +391,20 @@
The tags themselves are tool-specific and are defined further
below, for each tool.
-* The <what> tag gives a human-understandable description of the
- error. There may be two consecutive <what>TEXT</what> blocks, in
- which case the second block gives further details, and should be
- displayed by GUIs immediately following the first one.
+* The "(either WHAT or XWHAT)" gives a primary description of the
+ error. WHAT and XWHAT are described above.
-* Finally, optionally, a SUPPRESSION may be provided. This contains
- a suppression that would hide the error.
+* Optionally, a second line of primary description may be present.
+* A STACK gives the primary source location for the error.
+* There then follow zero or more "... tool-specific fields ...",
+ which provide further (auxiliary) information about the error.
+
+* Optionally, as the last field, a SUPPRESSION may be provided. This
+ contains a suppression that would hide the error.
+
+
====================================================================
ERROR definition for Memcheck
@@ -523,37 +598,72 @@
====================================================================
-ERROR definition for Helgrind
------------------------------
+TOOLSPECIFIC definition for Helgrind
+-------------------------------------
-The definition is:
+For Helgrind, a TOOLSPECIFIC may be one of two things:
- <error>
- <unique>HEX64</unique>
- <tid>INT</tid>
- <kind>KIND</kind>
- <what>TEXT</what> (either 1 or 2 times)
+TOOLSPECIFIC = either ERROR or ANNOUNCETHREAD
- STACK
- zero or more of (STACK or <auxwhat>TEXT</auxwhat>)
+ANNOUNCETHREAD
+--------------
- optionally: SUPPRESSION
- </error>
+The definition is
+ <announcethread>
+ <hthreadid>INT</hthreadid>
+ STACK
+ </announcethread>
-The first four fields and the last field are specified in "ERROR
-definition -- common fields" above. The remaining fields are as
-follows:
+This states the creation point of a thread, and gives it a unique
+"hthreadid", which may be referred to in subsequent ERRORs. Note that
-* The primary STACK for this error, indicating where it occurred.
+1. The appearance of ANNOUNCETHREAD does not mean that the thread was
+ actually created at that point relative to any preceding or
+ following ERRORs in the output stream -- in general the thread will
+ have been created arbitrarily earlier. Helgrind only "announces" a
+ thread when it needs to refer to it for the first time, in a
+ subsequent ERROR.
-* Some error types may have auxiliary information attached, expressed
- as an arbitrary sequence of (STACK or <auxwhat>TEXT</auxwhat>).
- These should be presented to the user in the sequence they appear in
- the file, as they are intended to be read top-to-bottom.
+2. The "hthreadid" is a number which uniquely identifies the thread
+ for the run - no other thread will have the same hthreadid. The
+ hthreadid is a Helgrind-specific piece of information and is
+ unrelated to the <tid> fields in the common part of an ERROR.
+ Be careful not to confuse the two.
+ERROR details for Helgrind
+--------------------------
+
+The "... tool-specific fields ..." for Helgrind consist of
+zero or more of "(either AUXWHAT or XAUXWHAT or STACK)".
+They should be shown to the user in the order they appear.
+
+
+XWHATs (for definition, see above) may contain the following extra
+components (along with the mandatory <text>...</text> component):
+
+* <hthreadid>INT</hthreadid> fields. These refer to ANNOUNCETHREADs
+ appearing previously in the scheme, and state the creation points of
+ the thread(s) concerned in the ERROR. Hence it should be possible
+ for GUIs to show users stacks of the creation points of all threads
+ involved in each ERROR.
+
+
+XAUXWHATs (for definition, see above) may contain the following extra
+components (along with the mandatory <text>...</text> component):
+
+* <hthreadid>INT</hthreadid>, same meaning as when referred to in
+ XWHAT
+
+* <file>TEXT</file>, as defined in FRAME
+
+* <line>INT</line>, as defined in FRAME
+
+* <dir>TEXT</dir>, as defined in FRAME
+
+
KIND for Helgrind
-----------------
This is a small enumeration indicating roughly the nature of an error.
|
|
From: <sv...@va...> - 2009-05-16 02:03:42
|
Author: sewardj
Date: 2009-05-16 02:35:13 +0100 (Sat, 16 May 2009)
New Revision: 9844
Log:
Add new yet another (v)printf variant: VG_(vcbprintf), which is like
vprintf, but sends its output to a completely arbitrary callback
function on a character-by-character basis.
Modified:
branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c
branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h
Modified: branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c 2009-05-13 08:35:54 UTC (rev 9843)
+++ branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c 2009-05-16 01:35:13 UTC (rev 9844)
@@ -256,6 +256,17 @@
}
+/* --------- vcbprintf --------- */
+
+void VG_(vcbprintf)( void(*char_sink)(HChar, void* opaque),
+ void* opaque,
+ const HChar* format, va_list vargs )
+{
+ (void) VG_(debugLog_vprintf)
+ ( char_sink, opaque, format, vargs );
+}
+
+
/* ---------------------------------------------------------------------
percentify()
------------------------------------------------------------------ */
Modified: branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h
===================================================================
--- branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h 2009-05-13 08:35:54 UTC (rev 9843)
+++ branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h 2009-05-16 01:35:13 UTC (rev 9844)
@@ -73,6 +73,12 @@
const HChar *format, va_list vargs )
PRINTF_CHECK(3, 0);
+/* 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),
+ void* opaque,
+ const HChar* format, va_list vargs );
+
/* These are the same as the non "_xml" versions above, except the
output goes on the selected XML output channel instead of the
normal one.
@@ -85,7 +91,6 @@
extern UInt VG_(printf_xml_no_f_c) ( const HChar *format, ... );
-
// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
// Right justifies in 'buf'.
extern void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[]);
|
|
From: <sv...@va...> - 2009-05-16 02:03:42
|
Author: sewardj
Date: 2009-05-16 02:55:20 +0100 (Sat, 16 May 2009)
New Revision: 9847
Log:
Should have been committed in r9846 (which was: add before_pp_Error to
the VG_(needs_xml_output).
Modified:
branches/MESSAGING_TIDYUP/include/pub_tool_tooliface.h
Modified: branches/MESSAGING_TIDYUP/include/pub_tool_tooliface.h
===================================================================
--- branches/MESSAGING_TIDYUP/include/pub_tool_tooliface.h 2009-05-16 01:50:48 UTC (rev 9846)
+++ branches/MESSAGING_TIDYUP/include/pub_tool_tooliface.h 2009-05-16 01:55:20 UTC (rev 9847)
@@ -424,7 +424,17 @@
/* Can the tool do XML output? This is a slight misnomer, because the tool
* is not requesting the core to do anything, rather saying "I can handle
* it". */
-extern void VG_(needs_xml_output)( void );
+extern void VG_(needs_xml_output)(
+ // We give tools a chance to have a look at errors
+ // just before they are printed. That is, before_pp_Error is
+ // called just before pp_Error itself. This gives the tool a chance
+ // to look at the just-about-to-be-printed error, so as to emit any
+ // arbitrary output they want to, before the error itself is
+ // printed. This functionality was added to allow Helgrind to print
+ // thread-announcement messages in XML form, but is in fact called
+ // regardless of whether or not we're in XML mode.
+ void (*before_pp_Error)( Error* )
+);
/* Does the tool want to have one final pass over the IR after tree
building but before instruction selection? If so specify the
|
|
From: <sv...@va...> - 2009-05-16 02:03:37
|
Author: sewardj
Date: 2009-05-16 02:50:48 +0100 (Sat, 16 May 2009)
New Revision: 9846
Log:
Change VG_(needs_xml_output), so as to give it a new method,
before_pp_Error. This gives tools the chance to inspect an error
which the core is just about to print using pp_Error, so it can
generate whatever preamble it likes. This is important for generating
thread announcements in Helgrind.
Hmm. Actually this doesn't have that much to do with XML any more;
Helgrind now uses it to generate thread announcements even in text
mode. Perhaps this method should be moved to the
VG_(needs_core_errors) group.
This change no doubt breaks the build (on this branch).
Modified:
branches/MESSAGING_TIDYUP/coregrind/m_tooliface.c
branches/MESSAGING_TIDYUP/coregrind/pub_core_tooliface.h
Modified: branches/MESSAGING_TIDYUP/coregrind/m_tooliface.c
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/m_tooliface.c 2009-05-16 01:42:30 UTC (rev 9845)
+++ branches/MESSAGING_TIDYUP/coregrind/m_tooliface.c 2009-05-16 01:50:48 UTC (rev 9846)
@@ -214,7 +214,6 @@
NEEDS(libc_freeres)
NEEDS(core_errors)
NEEDS(var_info)
-NEEDS(xml_output)
void VG_(needs_superblock_discards)(
void (*discard)(Addr64, VexGuestExtents)
@@ -316,6 +315,14 @@
VG_(tdict).tool_client_redzone_szB = client_malloc_redzone_szB;
}
+void VG_(needs_xml_output)(
+ void (*before_pp_Error)( Error* )
+)
+{
+ VG_(needs).xml_output = True;
+ VG_(tdict).tool_before_pp_Error = before_pp_Error;
+}
+
void VG_(needs_final_IR_tidy_pass)(
IRSB*(*final_tidy)(IRSB*)
)
Modified: branches/MESSAGING_TIDYUP/coregrind/pub_core_tooliface.h
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/pub_core_tooliface.h 2009-05-16 01:42:30 UTC (rev 9845)
+++ branches/MESSAGING_TIDYUP/coregrind/pub_core_tooliface.h 2009-05-16 01:50:48 UTC (rev 9846)
@@ -161,6 +161,9 @@
// VG_(needs).final_IR_tidy_pass
IRSB* (*tool_final_IR_tidy_pass) (IRSB*);
+ // VG_(needs).xml_output
+ void (*tool_before_pp_Error) (Error*);
+
// -- Event tracking functions ------------------------------------
void (*track_new_mem_startup) (Addr, SizeT, Bool, Bool, Bool, ULong);
void (*track_new_mem_stack_signal)(Addr, SizeT, ThreadId);
|