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
(9) |
2
(19) |
|
3
(5) |
4
(20) |
5
(5) |
6
(9) |
7
(6) |
8
(8) |
9
(5) |
|
10
(5) |
11
(5) |
12
(7) |
13
(7) |
14
(6) |
15
(5) |
16
(5) |
|
17
(5) |
18
(7) |
19
(21) |
20
(9) |
21
(6) |
22
(8) |
23
(6) |
|
24
(9) |
25
(9) |
26
(8) |
27
(19) |
28
(15) |
29
(8) |
30
(5) |
|
31
(6) |
|
|
|
|
|
|
|
From: James C. <cl...@cc...> - 2008-08-19 22:25:59
|
John, Thanks for the response. The final goal of the port isn't to use the current set of valgrind tools but to have a full featured dynamic binary instrumenter for Solaris / SPARC. I'm not aware of anything that meets that criteria. Maybe someone else knows something that does. The closest thing that I'm aware of is the dbx debugger's runtime checking. However, it doesn't look like it's designed to support custom tools. ~Jim On Aug 19, 2008, at 3:30 PM, John Reiser wrote: > James Clause wrote: >> I know there's no official port for Solaris / SPARC but does anyone >> know if there's at least a partial implementation somewhere? There's >> been a little bit of talk about it on various mailing lists but >> nothing concrete. >> >> If there's nothing available what would be the best way to start. I >> read that the suggested way to was to go from linux/x86 -> solaris/ >> x86 >> ->solaris/SPARC is this still true. And one final thing -- what >> would >> be a decent estimate for how much work / how long the port would take >> assuming decent knowledge of valgrind and the target platform? > > Be aware of the direct commercial competition on Solaris SPARC, > such as Purify and Quantify from IBM [Rational], and Insure++ from > Parasoft. > They do not cover every aspect of the valgrind milieu, but in many > environments they do the job very well. > > There are two major areas of work: the operating system, and the > hardware. > They are mostly separable, although they do overlap regarding the > arguments > and results for system calls. The path linux+x86 ==> solaris+x86 ==> > solaris+SPARC is nice because it gives an implementation for solaris > +x86. > Using linux+SPARC as a middle would be useful, too, but perhaps the > audience is smaller. Studying linux+PowerPC could be helpful because > both SPARC and PowerPC have fixed-length instructions. > > Find a partner (or two, but not more.) If you work together, and > only on this > project, then it should take a couple of months to get memcheck > running on > one small non-threaded C program. A complete implementation, > covering threads > and non-native execution, and all tools and all testcases and all > opcodes and > all system calls, and with only a short list of bugs, might take > three or four > times as long. > > -- |
|
From: John R.
|
James Clause wrote: > I know there's no official port for Solaris / SPARC but does anyone > know if there's at least a partial implementation somewhere? There's > been a little bit of talk about it on various mailing lists but > nothing concrete. > > If there's nothing available what would be the best way to start. I > read that the suggested way to was to go from linux/x86 -> solaris/x86 > ->solaris/SPARC is this still true. And one final thing -- what would > be a decent estimate for how much work / how long the port would take > assuming decent knowledge of valgrind and the target platform? Be aware of the direct commercial competition on Solaris SPARC, such as Purify and Quantify from IBM [Rational], and Insure++ from Parasoft. They do not cover every aspect of the valgrind milieu, but in many environments they do the job very well. There are two major areas of work: the operating system, and the hardware. They are mostly separable, although they do overlap regarding the arguments and results for system calls. The path linux+x86 ==> solaris+x86 ==> solaris+SPARC is nice because it gives an implementation for solaris+x86. Using linux+SPARC as a middle would be useful, too, but perhaps the audience is smaller. Studying linux+PowerPC could be helpful because both SPARC and PowerPC have fixed-length instructions. Find a partner (or two, but not more.) If you work together, and only on this project, then it should take a couple of months to get memcheck running on one small non-threaded C program. A complete implementation, covering threads and non-native execution, and all tools and all testcases and all opcodes and all system calls, and with only a short list of bugs, might take three or four times as long. -- |
|
From: <sv...@va...> - 2008-08-19 18:48:31
|
Author: sewardj Date: 2008-08-19 19:48:39 +0100 (Tue, 19 Aug 2008) New Revision: 8533 Log: Initial commit of the YARD implementation. Added: branches/YARD/helgrind/Makefile_sa branches/YARD/helgrind/README_MSMProp2.txt branches/YARD/helgrind/README_YARD.txt branches/YARD/helgrind/libhb.h branches/YARD/helgrind/libhb_core.c branches/YARD/helgrind/libhb_sa.c branches/YARD/helgrind/libhb_vg.c Modified: branches/YARD/helgrind/Makefile.am branches/YARD/helgrind/hg_main.c [... diff too large to include ...] |
|
From: James C. <cl...@cc...> - 2008-08-19 15:16:26
|
Hi, I know there's no official port for Solaris / SPARC but does anyone know if there's at least a partial implementation somewhere? There's been a little bit of talk about it on various mailing lists but nothing concrete. If there's nothing available what would be the best way to start. I read that the suggested way to was to go from linux/x86 -> solaris/x86 ->solaris/SPARC is this still true. And one final thing -- what would be a decent estimate for how much work / how long the port would take assuming decent knowledge of valgrind and the target platform? Thanks, Jim |
|
From: <sv...@va...> - 2008-08-19 13:21:46
|
Author: sewardj Date: 2008-08-19 14:21:53 +0100 (Tue, 19 Aug 2008) New Revision: 8532 Log: Make a copy of trunk r8531, for further experimentation with Helgrind. Added: branches/YARD/ Copied: branches/YARD (from rev 8531, trunk) Property changes on: branches/YARD ___________________________________________________________________ Name: svn:ignore + acinclude.m4 aclocal.m4 autom4te-*.cache autom4te.cache bin cachegrind cachegrind.out.* compile config.guess config.h* config.log config.status config.sub configure default.supp glibc-2.X.supp depcomp include .in_place install-sh lib Makefile Makefile.in missing mkinstalldirs share stamp-h* svn-commit.tmp svn-commit.2.tmp valgrind valgrind.pc valgrind.spec valt_load_address*.lds vg_annotate vg_cachegen Name: svn:externals + VEX svn://svn.valgrind.org/vex/trunk Name: svn:mergeinfo + |
|
From: <sv...@va...> - 2008-08-19 11:38:43
|
Author: sewardj
Date: 2008-08-19 12:38:51 +0100 (Tue, 19 Aug 2008)
New Revision: 8531
Log:
Extend the query side of m_debuginfo, so as to be able to extract
information on available stack and global variables, as in-scope
at a given program-counter value. Said information is obtained
from the Dwarf3 variable location/type information, of course.
Commit contains some fragments which are logically part of
r8529 (enhancement of the core-tool iface
events "new_mem_startup" and "new_mem_mmap"), but which cannot be
cleanly separated from the Dwarf3 var-info stuff because both
sets of changes are in the same source file.
Modified:
branches/SGCHECK/coregrind/m_debuginfo/d3basics.c
branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c
branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h
branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h
branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h
branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h
branches/SGCHECK/coregrind/pub_core_debuginfo.h
branches/SGCHECK/include/pub_tool_debuginfo.h
Modified: branches/SGCHECK/coregrind/m_debuginfo/d3basics.c
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/d3basics.c 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/d3basics.c 2008-08-19 11:38:51 UTC (rev 8531)
@@ -38,10 +38,12 @@
#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
#include "pub_core_options.h"
+#include "pub_core_xarray.h"
#include "pub_core_vki.h" /* VKI_PROT_READ */
#include "pub_core_aspacemgr.h" /* VG_(is_valid_for_client) */
+#include "priv_misc.h"
#include "priv_d3basics.h" /* self */
HChar* ML_(pp_DW_children) ( DW_children hashch )
@@ -674,6 +676,141 @@
}
+/* Evaluate a very simple Guarded (DWARF3) expression. The expression
+ is expected to denote a constant, with no reference to any
+ registers nor to any frame base expression. The expression is
+ expected to have at least one guard. If there is more than one
+ guard, all the sub-expressions are evaluated and compared. The
+ address ranges on the guards are ignored. GXR_Failure is returned
+ in the following circumstances:
+ * no guards
+ * any of the subexpressions require a frame base expression
+ * any of the subexpressions denote a register location
+ * any of the subexpressions do not produce a manifest constant
+ * there's more than one subexpression, all of which successfully
+ evaluate to a constant, but they don't all produce the same constant.
+ */
+GXResult ML_(evaluate_trivial_GX)( GExpr* gx, Addr data_bias )
+{
+ GXResult res;
+ Addr aMin, aMax;
+ UChar uc;
+ UShort nbytes;
+ Word i, nGuards;
+ MaybeUWord *muw, *muw2;
+
+ HChar* badness = NULL;
+ UChar* p = &gx->payload[0];
+ XArray* results = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
+ sizeof(MaybeUWord) );
+
+ uc = *p++; /*biasMe*/
+ vg_assert(uc == 0 || uc == 1);
+ /* in fact it's senseless to evaluate if the guards need biasing.
+ So don't. */
+ vg_assert(uc == 0);
+
+ nGuards = 0;
+ while (True) {
+ MaybeUWord thisResult;
+ uc = *p++;
+ if (uc == 1) /*isEnd*/
+ break;
+ vg_assert(uc == 0);
+ aMin = * (Addr*)p; p += sizeof(Addr);
+ aMax = * (Addr*)p; p += sizeof(Addr);
+ nbytes = * (UShort*)p; p += sizeof(UShort);
+ nGuards++;
+ if (0) VG_(printf)(" guard %ld: %#lx %#lx\n",
+ nGuards, aMin,aMax);
+
+ thisResult.b = False;
+ thisResult.w = 0;
+
+ /* Peer at this particular subexpression, to see if it's
+ obviously a constant. */
+ if (nbytes == 1 + sizeof(Addr) && *p == DW_OP_addr) {
+ thisResult.b = True;
+ thisResult.w = *(Addr*)(p+1) + data_bias;
+ }
+ else if (nbytes >= 1 && *p >= DW_OP_reg0 && *p <= DW_OP_reg31) {
+ if (!badness)
+ badness = "trivial GExpr denotes register (1)";
+ }
+ else if (nbytes >= 1 && *p == DW_OP_fbreg) {
+ if (!badness)
+ badness = "trivial GExpr requires fbGX";
+ }
+ else if (nbytes >= 1 && *p >= DW_OP_breg0 && *p <= DW_OP_breg31) {
+ if (!badness)
+ badness = "trivial GExpr requires register value";
+ }
+ else if (nbytes >= 1 && *p == DW_OP_regx) {
+ if (!badness)
+ badness = "trivial GExpr denotes register (2)";
+ }
+ else {
+ VG_(printf)(" ML_(evaluate_trivial_GX): unhandled:\n ");
+ ML_(pp_GX)( gx );
+ VG_(printf)("\n");
+ tl_assert(0);
+ }
+
+ VG_(addToXA)( results, &thisResult );
+
+ p += (UWord)nbytes;
+ }
+
+ res.kind = GXR_Failure;
+
+ tl_assert(nGuards == VG_(sizeXA)( results ));
+ tl_assert(nGuards >= 0);
+ if (nGuards == 0) {
+ tl_assert(!badness);
+ res.word = (UWord)"trivial GExpr has no guards (!)";
+ VG_(deleteXA)( results );
+ return res;
+ }
+
+ for (i = 0; i < nGuards; i++) {
+ muw = VG_(indexXA)( results, i );
+ if (muw->b == False)
+ break;
+ }
+
+ vg_assert(i >= 0 && i <= nGuards);
+ if (i < nGuards) {
+ /* at least one subexpression failed to produce a manifest constant. */
+ vg_assert(badness);
+ res.word = (UWord)badness;
+ VG_(deleteXA)( results );
+ return res;
+ }
+
+ /* All the subexpressions produced a constant, but did they all produce
+ the same one? */
+ muw = VG_(indexXA)( results, 0 );
+ tl_assert(muw->b == True); /* we just established that all exprs are ok */
+
+ for (i = 1; i < nGuards; i++) {
+ muw2 = VG_(indexXA)( results, i );
+ tl_assert(muw2->b == True);
+ if (muw2->w != muw->w) {
+ res.word = (UWord)"trivial GExpr: subexpressions disagree";
+ VG_(deleteXA)( results );
+ return res;
+ }
+ }
+
+ /* Well, we have success. All subexpressions evaluated, and
+ they all agree. Hurrah. */
+ res.kind = GXR_Value;
+ res.word = muw->w;
+ VG_(deleteXA)( results );
+ return res;
+}
+
+
void ML_(pp_GXResult) ( GXResult res )
{
switch (res.kind) {
Modified: branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/debuginfo.c 2008-08-19 11:38:51 UTC (rev 8531)
@@ -156,6 +156,11 @@
/*--- Notification (acquire/discard) helpers ---*/
/*------------------------------------------------------------*/
+/* Gives out unique abstract handles for allocated DebugInfos. See
+ comment in priv_storage.h, declaration of struct _DebugInfo, for
+ details. */
+static ULong handle_counter = 1;
+
/* Allocate and zero out a new DebugInfo record. */
static
DebugInfo* alloc_DebugInfo( const UChar* filename,
@@ -167,6 +172,7 @@
vg_assert(filename);
di = ML_(dinfo_zalloc)(sizeof(DebugInfo));
+ di->handle = handle_counter++;
di->filename = ML_(dinfo_strdup)(filename);
di->memname = memname ? ML_(dinfo_strdup)(memname)
: NULL;
@@ -479,14 +485,22 @@
will try load debug info if the mapping at 'a' belongs to Valgrind;
whereas normally (False) it will not do that. This allows us to
carefully control when the thing will read symbols from the
- Valgrind executable itself. */
+ Valgrind executable itself.
-void VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
+ If a call to VG_(di_notify_mmap) causes debug info to be read, then
+ the returned ULong is an abstract handle which can later be used to
+ refer to the debuginfo read as a result of this specific mapping,
+ in later queries to m_debuginfo. In this case the handle value
+ will be one or above. If the returned value is zero, no debug info
+ was read. */
+
+ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
{
NSegment const * seg;
HChar* filename;
Bool ok, is_rx_map, is_rw_map;
DebugInfo* di;
+ ULong di_handle;
SysRes fd;
Int nread;
HChar buf1k[1024];
@@ -512,12 +526,12 @@
/* Ignore non-file mappings */
if ( ! (seg->kind == SkFileC
|| (seg->kind == SkFileV && allow_SkFileV)) )
- return;
+ return 0;
/* If the file doesn't have a name, we're hosed. Give up. */
filename = VG_(am_get_filename)( (NSegment*)seg );
if (!filename)
- return;
+ return 0;
if (debug)
VG_(printf)("di_notify_mmap-2: %s\n", filename);
@@ -539,13 +553,13 @@
fake_di.filename = filename;
ML_(symerr)(&fake_di, True, "failed to stat64/stat this file");
}
- return;
+ return 0;
}
/* Finally, the point of all this stattery: if it's not a regular file,
don't try to read debug info from it. */
if (! VKI_S_ISREG(statbuf.st_mode))
- return;
+ return 0;
/* no uses of statbuf below here. */
@@ -561,25 +575,25 @@
fake_di.filename = filename;
ML_(symerr)(&fake_di, True, "can't open file to inspect ELF header");
}
- return;
+ return 0;
}
nread = VG_(read)( fd.res, buf1k, sizeof(buf1k) );
VG_(close)( fd.res );
if (nread == 0)
- return;
+ return 0;
if (nread < 0) {
DebugInfo fake_di;
VG_(memset)(&fake_di, 0, sizeof(fake_di));
fake_di.filename = filename;
ML_(symerr)(&fake_di, True, "can't read file to inspect ELF header");
- return;
+ return 0;
}
vg_assert(nread > 0 && nread <= sizeof(buf1k) );
/* We're only interested in mappings of ELF object files. */
if (!ML_(is_elf_object_file)( buf1k, (SizeT)nread ))
- return;
+ return 0;
/* Now we have to guess if this is a text-like mapping, a data-like
mapping, neither or both. The rules are:
@@ -634,7 +648,7 @@
/* If it is neither text-ish nor data-ish, we're not interested. */
if (!(is_rx_map || is_rw_map))
- return;
+ return 0;
/* See if we have a DebugInfo for this filename. If not,
create one. */
@@ -665,48 +679,58 @@
}
}
- if (di->have_rx_map && di->have_rw_map && !di->have_dinfo) {
+ /* If we don't have an rx and rw mapping, or if we already have
+ debuginfo for this mapping for whatever reason, go no
+ further. */
+ if ( ! (di->have_rx_map && di->have_rw_map && !di->have_dinfo) )
+ return 0;
- vg_assert(di->filename);
- TRACE_SYMTAB("\n");
- TRACE_SYMTAB("------ start ELF OBJECT "
- "------------------------------\n");
- TRACE_SYMTAB("------ name = %s\n", di->filename);
- TRACE_SYMTAB("\n");
+ /* Ok, so, finally, let's try to read the debuginfo. */
+ vg_assert(di->filename);
+ TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("------ start ELF OBJECT "
+ "------------------------------\n");
+ TRACE_SYMTAB("------ name = %s\n", di->filename);
+ TRACE_SYMTAB("\n");
- /* We're going to read symbols and debug info for the avma
- ranges [rx_map_avma, +rx_map_size) and [rw_map_avma,
- +rw_map_size). First get rid of any other DebugInfos which
- overlap either of those ranges (to avoid total confusion). */
- discard_DebugInfos_which_overlap_with( di );
+ /* We're going to read symbols and debug info for the avma
+ ranges [rx_map_avma, +rx_map_size) and [rw_map_avma,
+ +rw_map_size). First get rid of any other DebugInfos which
+ overlap either of those ranges (to avoid total confusion). */
+ discard_DebugInfos_which_overlap_with( di );
- /* .. and acquire new info. */
- ok = ML_(read_elf_debug_info)( di );
+ /* .. and acquire new info. */
+ ok = ML_(read_elf_debug_info)( di );
- if (ok) {
- TRACE_SYMTAB("\n------ Canonicalising the "
- "acquired info ------\n");
- /* prepare read data for use */
- ML_(canonicaliseTables)( di );
- /* notify m_redir about it */
- TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
- VG_(redir_notify_new_DebugInfo)( di );
- /* Note that we succeeded */
- di->have_dinfo = True;
- } else {
- TRACE_SYMTAB("\n------ ELF reading failed ------\n");
- /* Something went wrong (eg. bad ELF file). Should we delete
- this DebugInfo? No - it contains info on the rw/rx
- mappings, at least. */
- }
+ if (ok) {
- TRACE_SYMTAB("\n");
- TRACE_SYMTAB("------ name = %s\n", di->filename);
- TRACE_SYMTAB("------ end ELF OBJECT "
- "------------------------------\n");
- TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("\n------ Canonicalising the "
+ "acquired info ------\n");
+ /* prepare read data for use */
+ ML_(canonicaliseTables)( di );
+ /* notify m_redir about it */
+ TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
+ VG_(redir_notify_new_DebugInfo)( di );
+ /* Note that we succeeded */
+ di->have_dinfo = True;
+ tl_assert(di->handle > 0);
+ di_handle = di->handle;
+ } else {
+ TRACE_SYMTAB("\n------ ELF reading failed ------\n");
+ /* Something went wrong (eg. bad ELF file). Should we delete
+ this DebugInfo? No - it contains info on the rw/rx
+ mappings, at least. */
+ di_handle = 0;
}
+
+ TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("------ name = %s\n", di->filename);
+ TRACE_SYMTAB("------ end ELF OBJECT "
+ "------------------------------\n");
+ TRACE_SYMTAB("\n");
+
+ return di_handle;
}
@@ -1856,7 +1880,6 @@
dname1[n_dname-1] = dname2[n_dname-1] = 0;
}
-
/* 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
@@ -2012,7 +2035,7 @@
scope. */
for (di = debugInfo_list; di != NULL; di = di->next) {
OSet* global_scope;
- Int gs_size;
+ Word gs_size;
Addr zero;
DiAddrRange* global_arange;
Word i;
@@ -2186,6 +2209,372 @@
}
+//////////////////////////////////////////////////////////////////
+// //
+// Support for other kinds of queries to the Dwarf3 var info //
+// //
+//////////////////////////////////////////////////////////////////
+
+/* Figure out if the variable 'var' has a location that is linearly
+ dependent on a stack pointer value, or a frame pointer value, and
+ if it is, add a description of it to 'blocks'. Otherwise ignore
+ it. If 'arrays_only' is True, also ignore it unless it has an
+ array type. */
+
+static
+void analyse_deps ( /*MOD*/XArray* /* of FrameBlock */ blocks,
+ Addr ip, Addr data_bias, DiVariable* var,
+ Bool arrays_only )
+{
+ GXResult res_sp_6k, res_sp_7k, res_fp_6k, res_fp_7k;
+ RegSummary regs;
+ MaybeUWord muw;
+ Bool isVec;
+
+ Bool debug = False;
+ if (0&&debug)
+ VG_(printf)("adeps: var %s\n", var->name );
+
+ /* Figure out how big the variable is. */
+ muw = ML_(sizeOfType)(var->type);
+ /* if this var has a type whose size is unknown or zero, it should
+ never have been added. ML_(addVar) should have rejected it. */
+ vg_assert(muw.b == True);
+ vg_assert(muw.w > 0);
+
+ /* skip if non-array and we're only interested in arrays */
+ isVec = var->type->tag == Ty_Array;
+ if (arrays_only && !isVec) return;
+
+ if (0) {ML_(pp_Type_C_ishly)(var->type);
+ VG_(printf)(" %s\n", var->name);}
+
+ /* Do some test evaluations of the variable's location expression,
+ in order to guess whether it is sp-relative, fp-relative, or
+ none. A crude hack, which can be interpreted roughly as finding
+ the first derivative of the location expression w.r.t. the
+ supplied frame and stack pointer values. */
+ regs.fp = 0;
+ regs.ip = ip;
+ regs.sp = 6 * 1024;
+ res_sp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+
+ regs.fp = 0;
+ regs.ip = ip;
+ regs.sp = 7 * 1024;
+ res_sp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+
+ regs.fp = 6 * 1024;
+ regs.ip = ip;
+ regs.sp = 0;
+ res_fp_6k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+
+ regs.fp = 7 * 1024;
+ regs.ip = ip;
+ regs.sp = 0;
+ res_fp_7k = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+
+ vg_assert(res_sp_6k.kind == res_sp_7k.kind);
+ vg_assert(res_sp_6k.kind == res_fp_6k.kind);
+ vg_assert(res_sp_6k.kind == res_fp_7k.kind);
+
+ if (res_sp_6k.kind == GXR_Value) {
+ StackBlock block;
+ GXResult res;
+ UWord sp_delta = res_sp_7k.word - res_sp_6k.word;
+ UWord fp_delta = res_fp_7k.word - res_fp_6k.word;
+ tl_assert(sp_delta == 0 || sp_delta == 1024);
+ tl_assert(fp_delta == 0 || fp_delta == 1024);
+
+ if (sp_delta == 0 && fp_delta == 0) {
+ /* depends neither on sp nor fp, so it can't be a stack
+ local. Ignore it. */
+ }
+ else
+ if (sp_delta == 1024 && fp_delta == 0) {
+ regs.sp = regs.fp = 0;
+ regs.ip = ip;
+ res = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+ tl_assert(res.kind == GXR_Value);
+ if (debug)
+ VG_(printf)(" %5ld .. %5ld (sp) %s\n",
+ res.word, res.word + muw.w - 1, var->name);
+ block.base = res.word;
+ block.szB = muw.w;
+ block.spRel = True;
+ block.isVec = isVec;
+ VG_(memset)( &block.name[0], 0, sizeof(block.name) );
+ if (var->name)
+ VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 );
+ block.name[ sizeof(block.name)-1 ] = 0;
+ VG_(addToXA)( blocks, &block );
+ }
+ else
+ if (sp_delta == 0 && fp_delta == 1024) {
+ regs.sp = regs.fp = 0;
+ regs.ip = ip;
+ res = ML_(evaluate_GX)( var->gexpr, var->fbGX, ®s, data_bias );
+ tl_assert(res.kind == GXR_Value);
+ if (debug)
+ VG_(printf)(" %5ld .. %5ld (FP) %s\n",
+ res.word, res.word + muw.w - 1, var->name);
+ block.base = res.word;
+ block.szB = muw.w;
+ block.spRel = False;
+ block.isVec = isVec;
+ VG_(memset)( &block.name[0], 0, sizeof(block.name) );
+ if (var->name)
+ VG_(strncpy)( &block.name[0], var->name, sizeof(block.name)-1 );
+ block.name[ sizeof(block.name)-1 ] = 0;
+ VG_(addToXA)( blocks, &block );
+ }
+ else {
+ vg_assert(0);
+ }
+ }
+}
+
+
+/* Get an XArray of StackBlock which describe the stack (auto) blocks
+ for this ip. The caller is expected to free the XArray at some
+ point. If 'arrays_only' is True, only array-typed blocks are
+ returned; otherwise blocks of all types are returned. */
+
+void* /* really, XArray* of StackBlock */
+ VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only )
+{
+ /* This is a derivation of consider_vars_in_frame() above. */
+ Word i;
+ DebugInfo* di;
+ RegSummary regs;
+ Bool debug = False;
+
+ XArray* res = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
+ sizeof(StackBlock) );
+
+ static UInt n_search = 0;
+ static UInt n_steps = 0;
+ n_search++;
+ if (debug)
+ VG_(printf)("QQQQ: dgsbai: ip %#lx\n", ip);
+ /* first, find the DebugInfo that pertains to 'ip'. */
+ for (di = debugInfo_list; di; di = di->next) {
+ n_steps++;
+ /* text segment missing? unlikely, but handle it .. */
+ if (!di->text_present || di->text_size == 0)
+ continue;
+ /* Ok. So does this text mapping bracket the ip? */
+ if (di->text_avma <= ip && ip < di->text_avma + di->text_size)
+ break;
+ }
+
+ /* Didn't find it. Strange -- means ip is a code address outside
+ of any mapped text segment. Unlikely but not impossible -- app
+ could be generating code to run. */
+ if (!di)
+ return res; /* currently empty */
+
+ if (0 && ((n_search & 0x1) == 0))
+ VG_(printf)("VG_(di_get_stack_blocks_at_ip): %u searches, "
+ "%u DebugInfos looked at\n",
+ n_search, n_steps);
+ /* Start of performance-enhancing hack: once every ??? (chosen
+ hackily after profiling) successful searches, move the found
+ DebugInfo one step closer to the start of the list. This makes
+ future searches cheaper. */
+ if ((n_search & 0xFFFF) == 0) {
+ /* Move si one step closer to the start of the list. */
+ move_DebugInfo_one_step_forward( di );
+ }
+ /* End of performance-enhancing hack. */
+
+ /* any var info at all? */
+ if (!di->varinfo)
+ return res; /* currently empty */
+
+ /* Work through the scopes from most deeply nested outwards,
+ looking for code address ranges that bracket 'ip'. The
+ variables on each such address range found are in scope right
+ now. Don't descend to level zero as that is the global
+ scope. */
+ regs.ip = ip;
+ regs.sp = 0;
+ regs.fp = 0;
+
+ /* "for each scope, working outwards ..." */
+ for (i = VG_(sizeXA)(di->varinfo) - 1; i >= 1; i--) {
+ XArray* vars;
+ Word j;
+ DiAddrRange* arange;
+ OSet* this_scope
+ = *(OSet**)VG_(indexXA)( di->varinfo, i );
+ if (debug)
+ VG_(printf)("QQQQ: considering scope %ld\n", (Word)i);
+ if (!this_scope)
+ continue;
+ /* Find the set of variables in this scope that
+ bracket the program counter. */
+ arange = VG_(OSetGen_LookupWithCmp)(
+ this_scope, &ip,
+ ML_(cmp_for_DiAddrRange_range)
+ );
+ if (!arange)
+ continue;
+ /* stay sane */
+ vg_assert(arange->aMin <= arange->aMax);
+ /* It must bracket the ip we asked for, else
+ ML_(cmp_for_DiAddrRange_range) is somehow broken. */
+ vg_assert(arange->aMin <= ip && ip <= arange->aMax);
+ /* It must have an attached XArray of DiVariables. */
+ vars = arange->vars;
+ vg_assert(vars);
+ /* But it mustn't cover the entire address range. We only
+ expect that to happen for the global scope (level 0), which
+ we're not looking at here. Except, it may cover the entire
+ address range, but in that case the vars array must be
+ empty. */
+ vg_assert(! (arange->aMin == (Addr)0
+ && arange->aMax == ~(Addr)0
+ && VG_(sizeXA)(vars) > 0) );
+ for (j = 0; j < VG_(sizeXA)( vars ); j++) {
+ DiVariable* var = (DiVariable*)VG_(indexXA)( vars, j );
+ if (debug)
+ VG_(printf)("QQQQ: var:name=%s %#lx-%#lx %#lx\n",
+ var->name,arange->aMin,arange->aMax,ip);
+ analyse_deps( res, ip, di->data_bias, var, arrays_only );
+ }
+ }
+
+ return res;
+}
+
+
+/* Get an array of GlobalBlock which describe the global blocks owned
+ by the shared object characterised by the given di_handle. Asserts
+ if the handle is invalid. The caller is responsible for freeing
+ the array at some point. If 'arrays_only' is True, only
+ array-typed blocks are returned; otherwise blocks of all types are
+ returned. */
+
+void* /* really, XArray* of GlobalBlock */
+ VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle,
+ Bool arrays_only )
+{
+ /* This is a derivation of consider_vars_in_frame() above. */
+
+ DebugInfo* di;
+ XArray* gvars; /* XArray* of GlobalBlock */
+ Word nScopes, scopeIx;
+
+ /* The first thing to do is find the DebugInfo that
+ pertains to 'di_handle'. */
+ tl_assert(di_handle > 0);
+ for (di = debugInfo_list; di; di = di->next) {
+ if (di->handle == di_handle)
+ break;
+ }
+
+ /* If this fails, we were unable to find any DebugInfo with the
+ given handle. This is considered an error on the part of the
+ caller. */
+ tl_assert(di != NULL);
+
+ /* we'll put the collected variables in here. */
+ gvars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), sizeof(GlobalBlock) );
+ tl_assert(gvars);
+
+ /* any var info at all? */
+ if (!di->varinfo)
+ return gvars;
+
+ /* we'll iterate over all the variables we can find, even if
+ it seems senseless to visit stack-allocated variables */
+ /* Iterate over all scopes */
+ nScopes = VG_(sizeXA)( di->varinfo );
+ for (scopeIx = 0; scopeIx < nScopes; scopeIx++) {
+
+ /* Iterate over each (code) address range at the current scope */
+ DiAddrRange* range;
+ OSet* /* of DiAddrInfo */ scope
+ = *(OSet**)VG_(indexXA)( di->varinfo, scopeIx );
+ tl_assert(scope);
+ VG_(OSetGen_ResetIter)(scope);
+ while ( (range = VG_(OSetGen_Next)(scope)) ) {
+
+ /* Iterate over each variable in the current address range */
+ Word nVars, varIx;
+ tl_assert(range->vars);
+ nVars = VG_(sizeXA)( range->vars );
+ for (varIx = 0; varIx < nVars; varIx++) {
+
+ Bool isVec;
+ GXResult res;
+ MaybeUWord muw;
+ GlobalBlock gb;
+ DiVariable* var = VG_(indexXA)( range->vars, varIx );
+ tl_assert(var->name);
+ if (0) VG_(printf)("at depth %ld var %s ", scopeIx, var->name );
+
+ /* Now figure out if this variable has a constant address
+ (that is, independent of FP, SP, phase of moon, etc),
+ and if so, what the address is. Any variable with a
+ constant address is deemed to be a global so we collect
+ it. */
+ if (0) { VG_(printf)("EVAL: "); ML_(pp_GX)(var->gexpr);
+ VG_(printf)("\n"); }
+ res = ML_(evaluate_trivial_GX)( var->gexpr, di->data_bias );
+
+ /* Not a constant address => not interesting */
+ if (res.kind != GXR_Value) {
+ if (0) VG_(printf)("FAIL\n");
+ continue;
+ }
+
+ /* Ok, it's a constant address. See if we want to collect
+ it. */
+ if (0) VG_(printf)("%#lx\n", res.word);
+
+ /* Figure out how big the variable is. */
+ muw = ML_(sizeOfType)(var->type);
+
+ /* if this var has a type whose size is unknown or zero,
+ it should never have been added. ML_(addVar) should
+ have rejected it. */
+ vg_assert(muw.b == True);
+ vg_assert(muw.w > 0);
+
+ /* skip if non-array and we're only interested in
+ arrays */
+ isVec = var->type->tag == Ty_Array;
+ if (arrays_only && !isVec) continue;
+
+ /* Ok, so collect it! */
+ tl_assert(var->name);
+ tl_assert(di->soname);
+ VG_(printf)("XXXX %s %s %d\n", var->name,
+ var->fileName?(HChar*)var->fileName:"??",var->lineNo);
+ VG_(memset)(&gb, 0, sizeof(gb));
+ gb.addr = res.word;
+ gb.szB = muw.w;
+ gb.isVec = isVec;
+ VG_(strncpy)(&gb.name[0], var->name, sizeof(gb.name)-1);
+ VG_(strncpy)(&gb.soname[0], di->soname, sizeof(gb.soname)-1);
+ tl_assert(gb.name[ sizeof(gb.name)-1 ] == 0);
+ tl_assert(gb.soname[ sizeof(gb.soname)-1 ] == 0);
+
+ VG_(addToXA)( gvars, &gb );
+
+ } /* for (varIx = 0; varIx < nVars; varIx++) */
+
+ } /* while ( (range = VG_(OSetGen_Next)(scope)) ) */
+
+ } /* for (scopeIx = 0; scopeIx < nScopes; scopeIx++) */
+
+ return gvars;
+}
+
+
+
/*------------------------------------------------------------*/
/*--- DebugInfo accessor functions ---*/
/*------------------------------------------------------------*/
Modified: branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_d3basics.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -636,6 +636,15 @@
Addr data_bias,
Bool push_initial_zero );
+/* Evaluate a very simple Guarded (DWARF3) expression. The expression
+ is expected to denote a constant, with no reference to any
+ registers nor to any frame base expression. GXR_Failure is
+ returned if there is more than one guard, or none, a register
+ location is denoted, a frame base expression is required, or the
+ expression is not manifestly a constant. The range of addresses
+ covered by the guard is also ignored. */
+GXResult ML_(evaluate_trivial_GX)( GExpr* gx, Addr data_bias );
+
#endif /* ndef __PRIV_D3BASICS_H */
/*--------------------------------------------------------------------*/
Modified: branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_misc.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -42,7 +42,11 @@
void ML_(dinfo_free)( void* v );
UChar* ML_(dinfo_strdup)( const UChar* str );
+/* A handy type, a la Haskell's Maybe type. Yes, I know, C sucks.
+ Been there. Done that. Seen the movie. Got the T-shirt. Etc. */
+typedef struct { UWord w; Bool b; } MaybeUWord;
+
#endif /* ndef __PRIV_MISC_H */
/*--------------------------------------------------------------------*/
Modified: branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_storage.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -248,6 +248,16 @@
struct _DebugInfo* next; /* list of DebugInfos */
Bool mark; /* marked for deletion? */
+ /* An abstract handle, which can be used by entities outside of
+ m_debuginfo to (in an abstract datatype sense) refer to this
+ struct _DebugInfo. A .handle of zero is invalid; valid handles
+ are 1 and above. The same handle is never issued twice (in any
+ given run of Valgrind), so a handle becomes invalid when the
+ associated struct _DebugInfo is discarded, and remains invalid
+ forever thereafter. The .handle field is set as soon as this
+ structure is allocated. */
+ ULong handle;
+
/* Used for debugging only - indicate what stuff to dump whilst
reading stuff into the seginfo. Are computed as early in the
lifetime of the DebugInfo as possible -- at the point when it is
Modified: branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h
===================================================================
--- branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/m_debuginfo/priv_tytypes.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -152,9 +152,6 @@
/* How big is this type? (post-resolved only) If .b in the
returned struct is False, the size is unknown. */
/* FIXME: check all pointers before dereferencing */
-
-typedef struct { UWord w; Bool b; } MaybeUWord;
-
MaybeUWord ML_(sizeOfType)( Type* ty );
/* Describe where in the type 'offset' falls. Caller must
Modified: branches/SGCHECK/coregrind/pub_core_debuginfo.h
===================================================================
--- branches/SGCHECK/coregrind/pub_core_debuginfo.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/coregrind/pub_core_debuginfo.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -45,9 +45,16 @@
allow_SkFileV is True, it will try load debug info if the mapping
at 'a' belongs to Valgrind; whereas normally (False) it will not do
that. This allows us to carefully control when the thing will read
- symbols from the Valgrind executable itself. */
+ symbols from the Valgrind executable itself.
+
+ If a call to VG_(di_notify_mmap) causes debug info to be read, then
+ the returned ULong is an abstract handle which can later be used to
+ refer to the debuginfo read as a result of this specific mapping,
+ in later queries to m_debuginfo. In this case the handle value
+ will be one or above. If the returned value is zero, no debug info
+ was read. */
#if defined(VGO_linux)
-extern void VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV );
+extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV );
extern void VG_(di_notify_munmap)( Addr a, SizeT len );
@@ -59,17 +66,20 @@
parameters describe a code segment and its associated data segment,
that have recently been mapped in -- so we need to read debug info
for it -- or conversely, have recently been dumped, in which case
- the relevant debug info has to be unloaded. */
-extern void VG_(di_aix5_notify_segchange)(
- Addr code_start,
- Word code_len,
- Addr data_start,
- Word data_len,
- UChar* file_name,
- UChar* mem_name,
- Bool is_mainexe,
- Bool acquire
- );
+ the relevant debug info has to be unloaded.
+
+ The returned ULong has the same meaning as documented for
+ VG_(di_notify_mmap) just above. */
+extern ULong VG_(di_aix5_notify_segchange)(
+ Addr code_start,
+ Word code_len,
+ Addr data_start,
+ Word data_len,
+ UChar* file_name,
+ UChar* mem_name,
+ Bool is_mainexe,
+ Bool acquire
+ );
#endif
extern Bool VG_(get_fnname_nodemangle)( Addr a,
Modified: branches/SGCHECK/include/pub_tool_debuginfo.h
===================================================================
--- branches/SGCHECK/include/pub_tool_debuginfo.h 2008-08-19 11:32:30 UTC (rev 8530)
+++ branches/SGCHECK/include/pub_tool_debuginfo.h 2008-08-19 11:38:51 UTC (rev 8531)
@@ -105,6 +105,48 @@
*/
extern Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf);
+
+/* Get an XArray of StackBlock which describe the stack (auto) blocks
+ for this ip. The caller is expected to free the XArray at some
+ point. If 'arrays_only' is True, only array-typed blocks are
+ returned; otherwise blocks of all types are returned. */
+
+typedef
+ struct {
+ OffT base; /* offset from sp or fp */
+ SizeT szB; /* size in bytes */
+ Bool spRel; /* True => sp-rel, False => fp-rel */
+ Bool isVec; /* does block have an array type, or not? */
+ HChar name[16]; /* first 15 chars of name (asciiz) */
+ }
+ StackBlock;
+
+extern void* /* really, XArray* of StackBlock */
+ VG_(di_get_stack_blocks_at_ip)( Addr ip, Bool arrays_only );
+
+
+/* Get an array of GlobalBlock which describe the global blocks owned
+ by the shared object characterised by the given di_handle. Asserts
+ if the handle is invalid. The caller is responsible for freeing
+ the array at some point. If 'arrays_only' is True, only
+ array-typed blocks are returned; otherwise blocks of all types are
+ returned. */
+
+typedef
+ struct {
+ Addr addr;
+ SizeT szB;
+ Bool isVec; /* does block have an array type, or not? */
+ HChar name[16]; /* first 15 chars of name (asciiz) */
+ HChar soname[16]; /* first 15 chars of name (asciiz) */
+ }
+ GlobalBlock;
+
+extern void* /* really, XArray* of GlobalBlock */
+VG_(di_get_global_blocks_from_dihandle) ( ULong di_handle,
+ Bool arrays_only );
+
+
/*====================================================================*/
/*=== Obtaining segment information ===*/
/*====================================================================*/
|
|
From: <sv...@va...> - 2008-08-19 11:32:20
|
Author: sewardj
Date: 2008-08-19 12:32:30 +0100 (Tue, 19 Aug 2008)
New Revision: 8530
Log:
Build system changes for exp-sgcheck.
Modified:
branches/SGCHECK/Makefile.am
branches/SGCHECK/configure.in
Modified: branches/SGCHECK/Makefile.am
===================================================================
--- branches/SGCHECK/Makefile.am 2008-08-19 11:29:32 UTC (rev 8529)
+++ branches/SGCHECK/Makefile.am 2008-08-19 11:32:30 UTC (rev 8530)
@@ -12,7 +12,7 @@
helgrind \
drd
-EXP_TOOLS = exp-omega
+EXP_TOOLS = exp-omega exp-sgcheck
# Put docs last because building the HTML is slow and we want to get
# everything else working before we try it.
Modified: branches/SGCHECK/configure.in
===================================================================
--- branches/SGCHECK/configure.in 2008-08-19 11:29:32 UTC (rev 8529)
+++ branches/SGCHECK/configure.in 2008-08-19 11:32:30 UTC (rev 8530)
@@ -8,7 +8,7 @@
##------------------------------------------------------------##
# Process this file with autoconf to produce a configure script.
-AC_INIT(Valgrind, 3.4.0.SVN, val...@li...)
+AC_INIT(Valgrind, 3.4.0.SVN-SGCHECK, val...@li...)
AC_CONFIG_SRCDIR(coregrind/m_main.c)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE([foreign])
@@ -1518,6 +1518,9 @@
exp-omega/Makefile
exp-omega/tests/Makefile
exp-omega/docs/Makefile
+ exp-sgcheck/Makefile
+ exp-sgcheck/tests/Makefile
+ exp-sgcheck/docs/Makefile
drd/Makefile
drd/docs/Makefile
drd/scripts/download-and-build-splash2
|
|
From: <sv...@va...> - 2008-08-19 11:29:25
|
Author: sewardj
Date: 2008-08-19 12:29:32 +0100 (Tue, 19 Aug 2008)
New Revision: 8529
Log:
A small addition to the core/tool interface, needed to support
the SGcheck tool. If affects only the "new_mem_startup"
and "new_mem_mmap" events. When a new mmap happens, and for the
equivalent startup events, the debuginfo reader may choose to load
debug info associated with the mapped object.
This commit adds an extra parameter to the abovementioned events,
which is a 64-bit abstract handle that can later be used to refer
to the associated debuginfo that got loaded. This allows tools
to be aware of when debuginfo gets loaded, so that they can make
further queries to m_debuginfo if they like, before allowing execution
of the client to continue.
Patch is not cleanly separated from other changes (unfortunately)
and so is not standalone.
Modified:
branches/SGCHECK/coregrind/m_main.c
branches/SGCHECK/coregrind/m_syswrap/syswrap-generic.c
branches/SGCHECK/coregrind/m_tooliface.c
branches/SGCHECK/coregrind/pub_core_tooliface.h
branches/SGCHECK/drd/drd_main.c
branches/SGCHECK/helgrind/hg_main.c
branches/SGCHECK/include/pub_tool_tooliface.h
branches/SGCHECK/memcheck/mc_main.c
Modified: branches/SGCHECK/coregrind/m_main.c
===================================================================
--- branches/SGCHECK/coregrind/m_main.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/coregrind/m_main.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -1125,6 +1125,11 @@
static IIFinaliseImageInfo the_iifii;
+/* A simple pair structure, used for conveying debuginfo handles to
+ calls to VG_TRACK(new_mem_startup, ...). */
+typedef struct { Addr a; ULong ull; } Addr_n_ULong;
+
+
/* --- Forwards decls to do with shutdown --- */
static void final_tidyup(ThreadId tid);
@@ -1185,6 +1190,7 @@
Int loglevel, i;
Bool logging_to_fd;
struct vki_rlimit zero = { 0, 0 };
+ XArray* addr2dihandle = NULL;
//============================================================
//
@@ -1711,11 +1717,28 @@
// p: setup_code_redirect_table [so that redirs can be recorded]
// p: mallocfree
// p: probably: setup fds and process CLOs, so that logging works
+ //
+ // While doing this, make a note of the debuginfo-handles that
+ // come back from VG_(di_notify_mmap)/VG_(di_aix5_notify_segchange).
+ // Later, in "Tell the tool about the initial client memory permissions"
+ // (just below) we can then hand these handles off to the tool in
+ // calls to VG_TRACK(new_mem_startup, ...). This gives the tool the
+ // opportunity to make further queries to m_debuginfo before the
+ // client is started, if it wants. We put this information into an
+ // XArray, each handle along with the associated segment start address,
+ // and search the XArray for the handles later, when calling
+ // VG_TRACK(new_mem_startup, ...).
//--------------------------------------------------------------
VG_(debugLog)(1, "main", "Load initial debug info\n");
+
+ tl_assert(!addr2dihandle);
+ addr2dihandle = VG_(newXA)( VG_(malloc), VG_(free), sizeof(Addr_n_ULong) );
+ tl_assert(addr2dihandle);
+
# if defined(VGO_linux)
{ Addr* seg_starts;
Int n_seg_starts;
+ Addr_n_ULong anu;
seg_starts = get_seg_starts( &n_seg_starts );
vg_assert(seg_starts && n_seg_starts >= 0);
@@ -1723,14 +1746,22 @@
/* show them all to the debug info reader. allow_SkFileV has to
be True here so that we read info from the valgrind executable
itself. */
- for (i = 0; i < n_seg_starts; i++)
- VG_(di_notify_mmap)( seg_starts[i], True/*allow_SkFileV*/ );
+ for (i = 0; i < n_seg_starts; i++) {
+ anu.ull = VG_(di_notify_mmap)( seg_starts[i], True/*allow_SkFileV*/ );
+ /* anu.ull holds the debuginfo handle returned by di_notify_mmap,
+ if any. */
+ if (anu.ull > 0) {
+ anu.a = seg_starts[i];
+ VG_(addToXA)( addr2dihandle, &anu );
+ }
+ }
VG_(free)( seg_starts );
}
# elif defined(VGO_aix5)
{ AixCodeSegChange* changes;
Int changes_size, changes_used;
+ Addr_n_ULong anu;
/* Find out how many AixCodeSegChange records we will need,
and acquire them. */
@@ -1743,17 +1774,23 @@
vg_assert(changes_used >= 0 && changes_used <= changes_size);
/* And notify m_debuginfo of the changes. */
- for (i = 0; i < changes_used; i++)
- VG_(di_aix5_notify_segchange)(
- changes[i].code_start,
- changes[i].code_len,
- changes[i].data_start,
- changes[i].data_len,
- changes[i].file_name,
- changes[i].mem_name,
- changes[i].is_mainexe,
- changes[i].acquire
- );
+ for (i = 0; i < changes_used; i++) {
+ anu.ull = VG_(di_aix5_notify_segchange)(
+ changes[i].code_start,
+ changes[i].code_len,
+ changes[i].data_start,
+ changes[i].data_len,
+ changes[i].file_name,
+ changes[i].mem_name,
+ changes[i].is_mainexe,
+ changes[i].acquire
+ );
+ if (anu.ull > 0) {
+ tl_assert(changes[i].acquire);
+ anu.a = changes[i].code_start; /* is this correct? */
+ VG_(addToXA)( addr2dihandle, &anu );
+ }
+ }
VG_(free)(changes);
}
@@ -1797,11 +1834,18 @@
// p: mallocfree
// p: setup_client_stack
// p: setup_client_dataseg
+ //
+ // For each segment we tell the client about, look up in
+ // addr2dihandle as created above, to see if there's a debuginfo
+ // handle associated with the segment, that we can hand along
+ // to the tool, to be helpful.
//--------------------------------------------------------------
VG_(debugLog)(1, "main", "Tell tool about initial permissions\n");
{ Addr* seg_starts;
Int n_seg_starts;
+ tl_assert(addr2dihandle);
+
/* Mark the main thread as running while we tell the tool about
the client memory so that the tool can associate that memory
with the main thread. */
@@ -1813,9 +1857,11 @@
/* show interesting ones to the tool */
for (i = 0; i < n_seg_starts; i++) {
+ Word j, n;
NSegment const* seg
= VG_(am_find_nsegment)( seg_starts[i] );
vg_assert(seg);
+ vg_assert(seg->start == seg_starts[i] );
if (seg->kind == SkFileC || seg->kind == SkAnonC) {
VG_(debugLog)(2, "main",
"tell tool about %010lx-%010lx %c%c%c\n",
@@ -1823,12 +1869,28 @@
seg->hasR ? 'r' : '-',
seg->hasW ? 'w' : '-',
seg->hasX ? 'x' : '-' );
+ /* search addr2dihandle to see if we have an entry
+ matching seg->start. */
+ n = VG_(sizeXA)( addr2dihandle );
+ for (j = 0; j < n; j++) {
+ Addr_n_ULong* anl = VG_(indexXA)( addr2dihandle, j );
+ if (anl->a == seg->start) {
+ tl_assert(anl->ull > 0); /* check it's a valid handle */
+ break;
+ }
+ }
+ vg_assert(j >= 0 && j <= n);
VG_TRACK( new_mem_startup, seg->start, seg->end+1-seg->start,
- seg->hasR, seg->hasW, seg->hasX );
+ seg->hasR, seg->hasW, seg->hasX,
+ /* and the retrieved debuginfo handle, if any */
+ j < n
+ ? ((Addr_n_ULong*)VG_(indexXA)( addr2dihandle, j ))->ull
+ : 0 );
}
}
VG_(free)( seg_starts );
+ VG_(deleteXA)( addr2dihandle );
/* Also do the initial stack permissions. */
{ NSegment const* seg
@@ -1865,7 +1927,8 @@
- (Addr)&VG_(trampoline_stuff_start),
False, /* readable? */
False, /* writable? */
- True /* executable? */ );
+ True /* executable? */,
+ 0 /* di_handle: no associated debug info */ );
/* Clear the running thread indicator */
VG_(running_tid) = VG_INVALID_THREADID;
Modified: branches/SGCHECK/coregrind/m_syswrap/syswrap-generic.c
===================================================================
--- branches/SGCHECK/coregrind/m_syswrap/syswrap-generic.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/coregrind/m_syswrap/syswrap-generic.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -65,7 +65,8 @@
void notify_aspacem_of_mmap(Addr a, SizeT len, UInt prot,
UInt flags, Int fd, Off64T offset);
static
-void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset);
+void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset,
+ ULong di_handle);
/* Returns True iff address range is something the client can
@@ -151,13 +152,22 @@
/* When a client mmap has been successfully done, this function must
be called. It notifies both aspacem and the tool of the new
mapping.
-*/
+
+ JRS 2008-Aug-14: But notice this is *very* obscure. The only place
+ it is called from is POST(sys_io_setup). In particular,
+ ML_(generic_PRE_sys_mmap), further down in this file, is the
+ "normal case" handler for client mmap. But it doesn't call this
+ function; instead it does the relevant notifications itself. Here,
+ we just pass di_handle=0 to notify_tool_of_mmap as we have no
+ better information. But really this function should be done away
+ with; problem is I don't understand what POST(sys_io_setup) does or
+ how it works. */
void
ML_(notify_aspacem_and_tool_of_mmap) ( Addr a, SizeT len, UInt prot,
UInt flags, Int fd, Off64T offset )
{
notify_aspacem_of_mmap(a, len, prot, flags, fd, offset);
- notify_tool_of_mmap(a, len, prot, offset);
+ notify_tool_of_mmap(a, len, prot, offset, 0/*di_handle*/);
}
static
@@ -179,7 +189,8 @@
}
static
-void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset)
+void notify_tool_of_mmap(Addr a, SizeT len, UInt prot, Off64T offset,
+ ULong di_handle)
{
Bool rr, ww, xx;
@@ -192,7 +203,7 @@
ww = toBool(prot & VKI_PROT_WRITE);
xx = toBool(prot & VKI_PROT_EXEC);
- VG_TRACK( new_mem_mmap, a, len, rr, ww, xx );
+ VG_TRACK( new_mem_mmap, a, len, rr, ww, xx, di_handle );
}
/* Expand (or shrink) an existing mapping, potentially moving it at
@@ -332,7 +343,8 @@
MIN_SIZET(old_len,new_len) );
if (new_len > old_len)
VG_TRACK( new_mem_mmap, new_addr+old_len, new_len-old_len,
- old_seg->hasR, old_seg->hasW, old_seg->hasX );
+ old_seg->hasR, old_seg->hasW, old_seg->hasX,
+ 0/*di_handle*/ );
VG_TRACK(die_mem_munmap, old_addr, old_len);
if (d) {
VG_(discard_translations)( old_addr, old_len, "do_remap(1)" );
@@ -375,7 +387,8 @@
if (ok) {
VG_TRACK( new_mem_mmap, needA, needL,
old_seg->hasR,
- old_seg->hasW, old_seg->hasX );
+ old_seg->hasW, old_seg->hasX,
+ 0/*di_handle*/ );
if (d)
VG_(discard_translations)( needA, needL, "do_remap(3)" );
return VG_(mk_SysRes_Success)( old_addr );
@@ -395,7 +408,8 @@
MIN_SIZET(old_len,new_len) );
if (new_len > old_len)
VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len,
- old_seg->hasR, old_seg->hasW, old_seg->hasX );
+ old_seg->hasR, old_seg->hasW, old_seg->hasX,
+ 0/*di_handle*/ );
VG_TRACK(die_mem_munmap, old_addr, old_len);
if (d) {
VG_(discard_translations)( old_addr, old_len, "do_remap(4)" );
@@ -434,7 +448,8 @@
if (!ok)
goto eNOMEM;
VG_TRACK( new_mem_mmap, needA, needL,
- old_seg->hasR, old_seg->hasW, old_seg->hasX );
+ old_seg->hasR, old_seg->hasW, old_seg->hasX,
+ 0/*di_handle*/ );
if (d)
VG_(discard_translations)( needA, needL, "do_remap(6)" );
return VG_(mk_SysRes_Success)( old_addr );
@@ -1722,7 +1737,8 @@
/* we don't distinguish whether it's read-only or
* read-write -- it doesn't matter really. */
- VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False );
+ VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False,
+ 0/*di_handle*/ );
if (d)
VG_(discard_translations)( (Addr64)res,
(ULong)VG_PGROUNDUP(segmentSize),
@@ -1937,6 +1953,7 @@
}
if (!sres.isError) {
+ ULong di_handle;
/* Notify aspacem. */
notify_aspacem_of_mmap(
(Addr)sres.res, /* addr kernel actually assigned */
@@ -1947,13 +1964,15 @@
arg6 /* offset */
);
/* Load symbols? */
- VG_(di_notify_mmap)( (Addr)sres.res, False/*allow_SkFileV*/ );
+ di_handle = VG_(di_notify_mmap)( (Addr)sres.res, False/*allow_SkFileV*/ );
/* Notify the tool. */
notify_tool_of_mmap(
(Addr)sres.res, /* addr kernel actually assigned */
arg2, /* length */
arg3, /* prot */
- arg6 /* offset */
+ arg6, /* offset */
+ di_handle /* so the tool can refer to the read debuginfo later,
+ if it wants. */
);
}
Modified: branches/SGCHECK/coregrind/m_tooliface.c
===================================================================
--- branches/SGCHECK/coregrind/m_tooliface.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/coregrind/m_tooliface.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -340,10 +340,10 @@
VG_(tdict).fn = f; \
}
-DEF0(track_new_mem_startup, Addr, SizeT, Bool, Bool, Bool)
+DEF0(track_new_mem_startup, Addr, SizeT, Bool, Bool, Bool, ULong)
DEF0(track_new_mem_stack_signal, Addr, SizeT, UInt)
DEF0(track_new_mem_brk, Addr, SizeT, UInt)
-DEF0(track_new_mem_mmap, Addr, SizeT, Bool, Bool, Bool)
+DEF0(track_new_mem_mmap, Addr, SizeT, Bool, Bool, Bool, ULong)
DEF0(track_copy_mem_remap, Addr, Addr, SizeT)
DEF0(track_change_mem_mprotect, Addr, SizeT, Bool, Bool, Bool)
Modified: branches/SGCHECK/coregrind/pub_core_tooliface.h
===================================================================
--- branches/SGCHECK/coregrind/pub_core_tooliface.h 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/coregrind/pub_core_tooliface.h 2008-08-19 11:29:32 UTC (rev 8529)
@@ -161,10 +161,10 @@
IRSB* (*tool_final_IR_tidy_pass) (IRSB*);
// -- Event tracking functions ------------------------------------
- void (*track_new_mem_startup) (Addr, SizeT, Bool, Bool, Bool);
+ void (*track_new_mem_startup) (Addr, SizeT, Bool, Bool, Bool, ULong);
void (*track_new_mem_stack_signal)(Addr, SizeT, ThreadId);
void (*track_new_mem_brk) (Addr, SizeT, ThreadId);
- void (*track_new_mem_mmap) (Addr, SizeT, Bool, Bool, Bool);
+ void (*track_new_mem_mmap) (Addr, SizeT, Bool, Bool, Bool, ULong);
void (*track_copy_mem_remap) (Addr src, Addr dst, SizeT);
void (*track_change_mem_mprotect) (Addr, SizeT, Bool, Bool, Bool);
Modified: branches/SGCHECK/drd/drd_main.c
===================================================================
--- branches/SGCHECK/drd/drd_main.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/drd/drd_main.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -548,7 +548,8 @@
static
void drd_start_using_mem_w_perms(const Addr a, const SizeT len,
- const Bool rr, const Bool ww, const Bool xx)
+ const Bool rr, const Bool ww, const Bool xx,
+ ULong di_handle)
{
thread_set_vg_running_tid(VG_(get_running_tid)());
Modified: branches/SGCHECK/helgrind/hg_main.c
===================================================================
--- branches/SGCHECK/helgrind/hg_main.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/helgrind/hg_main.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -5435,7 +5435,7 @@
static
void evh__new_mem_w_perms ( Addr a, SizeT len,
- Bool rr, Bool ww, Bool xx ) {
+ Bool rr, Bool ww, Bool xx, ULong di_handle ) {
if (SHOW_EVENTS >= 1)
VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
(void*)a, len, (Int)rr, (Int)ww, (Int)xx );
Modified: branches/SGCHECK/include/pub_tool_tooliface.h
===================================================================
--- branches/SGCHECK/include/pub_tool_tooliface.h 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/include/pub_tool_tooliface.h 2008-08-19 11:29:32 UTC (rev 8529)
@@ -471,15 +471,24 @@
These ones occur at startup, upon some signals, and upon some syscalls.
- For the new_mem_brk and new_mem_stack_signal, the supplied ThreadId
+ For new_mem_brk and new_mem_stack_signal, the supplied ThreadId
indicates the thread for whom the new memory is being allocated.
+
+ For new_mem_startup and new_mem_mmap, the di_handle argument is a
+ handle which can be used to retrieve debug info associated with the
+ mapping or allocation (because it is of a file that Valgrind has
+ decided to read debug info from). If the value is zero, there is
+ no associated debug info. If the value exceeds zero, it can be
+ supplied as an argument to selected queries in m_debuginfo.
*/
void VG_(track_new_mem_startup) (void(*f)(Addr a, SizeT len,
- Bool rr, Bool ww, Bool xx));
+ Bool rr, Bool ww, Bool xx,
+ ULong di_handle));
void VG_(track_new_mem_stack_signal)(void(*f)(Addr a, SizeT len, ThreadId tid));
void VG_(track_new_mem_brk) (void(*f)(Addr a, SizeT len, ThreadId tid));
void VG_(track_new_mem_mmap) (void(*f)(Addr a, SizeT len,
- Bool rr, Bool ww, Bool xx));
+ Bool rr, Bool ww, Bool xx,
+ ULong di_handle));
void VG_(track_copy_mem_remap) (void(*f)(Addr from, Addr to, SizeT len));
void VG_(track_change_mem_mprotect) (void(*f)(Addr a, SizeT len,
Modified: branches/SGCHECK/memcheck/mc_main.c
===================================================================
--- branches/SGCHECK/memcheck/mc_main.c 2008-08-19 11:20:35 UTC (rev 8528)
+++ branches/SGCHECK/memcheck/mc_main.c 2008-08-19 11:29:32 UTC (rev 8529)
@@ -3654,7 +3654,8 @@
}
static
-void mc_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
+void mc_new_mem_startup( Addr a, SizeT len,
+ Bool rr, Bool ww, Bool xx, ULong di_handle )
{
/* Ignore the permissions, just make it defined. Seems to work... */
// Because code is defined, initialised variables get put in the data
@@ -3673,7 +3674,8 @@
}
static
-void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
+void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
+ ULong di_handle )
{
MC_(make_mem_defined)(a, len);
}
|
|
From: <sv...@va...> - 2008-08-19 11:20:28
|
Author: sewardj
Date: 2008-08-19 12:20:35 +0100 (Tue, 19 Aug 2008)
New Revision: 8528
Log:
Add the SGcheck tool; now reasonably robust, but can be very slow.
Added:
branches/SGCHECK/exp-sgcheck/
branches/SGCHECK/exp-sgcheck/Makefile.am
branches/SGCHECK/exp-sgcheck/docs/
branches/SGCHECK/exp-sgcheck/docs/Makefile.am
branches/SGCHECK/exp-sgcheck/sg_intercepts.c
branches/SGCHECK/exp-sgcheck/sg_main.c
branches/SGCHECK/exp-sgcheck/tests/
branches/SGCHECK/exp-sgcheck/tests/Makefile.am
Added: branches/SGCHECK/exp-sgcheck/Makefile.am
===================================================================
--- branches/SGCHECK/exp-sgcheck/Makefile.am (rev 0)
+++ branches/SGCHECK/exp-sgcheck/Makefile.am 2008-08-19 11:20:35 UTC (rev 8528)
@@ -0,0 +1,124 @@
+include $(top_srcdir)/Makefile.tool.am
+
+noinst_PROGRAMS =
+if VGP_X86_LINUX
+noinst_PROGRAMS += exp-sgcheck-x86-linux vgpreload_exp-sgcheck-x86-linux.so
+endif
+if VGP_AMD64_LINUX
+noinst_PROGRAMS += exp-sgcheck-amd64-linux vgpreload_exp-sgcheck-amd64-linux.so
+endif
+if VGP_PPC32_LINUX
+noinst_PROGRAMS += exp-sgcheck-ppc32-linux vgpreload_exp-sgcheck-ppc32-linux.so
+endif
+if VGP_PPC64_LINUX
+noinst_PROGRAMS += exp-sgcheck-ppc64-linux vgpreload_exp-sgcheck-ppc64-linux.so
+endif
+if VGP_PPC32_AIX5
+noinst_PROGRAMS += exp-sgcheck-ppc32-aix5 vgpreload_exp-sgcheck-ppc32-aix5.so
+endif
+if VGP_PPC64_AIX5
+noinst_PROGRAMS += exp-sgcheck-ppc64-aix5 vgpreload_exp-sgcheck-ppc64-aix5.so
+endif
+
+
+VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON = sg_intercepts.c
+
+vgpreload_exp_sgcheck_x86_linux_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_x86_linux_so_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
+vgpreload_exp_sgcheck_x86_linux_so_CFLAGS = $(AM_CFLAGS_X86_LINUX) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_x86_linux_so_CCASFLAGS = $(AM_CCASFLAGS_X86_LINUX)
+vgpreload_exp_sgcheck_x86_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_LINUX)
+vgpreload_exp_sgcheck_x86_linux_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_X86_LINUX) \
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_LINUX)
+
+vgpreload_exp_sgcheck_amd64_linux_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_amd64_linux_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_LINUX)
+vgpreload_exp_sgcheck_amd64_linux_so_CFLAGS = $(AM_CFLAGS_AMD64_LINUX) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_amd64_linux_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_LINUX)
+vgpreload_exp_sgcheck_amd64_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_LINUX)
+vgpreload_exp_sgcheck_amd64_linux_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_AMD64_LINUX) \
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_LINUX)
+
+vgpreload_exp_sgcheck_ppc32_linux_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_ppc32_linux_so_CPPFLAGS = $(AM_CPPFLAGS_PPC32_LINUX)
+vgpreload_exp_sgcheck_ppc32_linux_so_CFLAGS = $(AM_CFLAGS_PPC32_LINUX) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_ppc32_linux_so_CCASFLAGS = $(AM_CCASFLAGS_PPC32_LINUX)
+vgpreload_exp_sgcheck_ppc32_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC32_LINUX)
+vgpreload_exp_sgcheck_ppc32_linux_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_PPC32_LINUX) \
+ $(LIBREPLACEMALLOC_LDFLAGS_PPC32_LINUX)
+
+vgpreload_exp_sgcheck_ppc64_linux_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_ppc64_linux_so_CPPFLAGS = $(AM_CPPFLAGS_PPC64_LINUX)
+vgpreload_exp_sgcheck_ppc64_linux_so_CFLAGS = $(AM_CFLAGS_PPC64_LINUX) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_ppc64_linux_so_CCASFLAGS = $(AM_CCASFLAGS_PPC64_LINUX)
+vgpreload_exp_sgcheck_ppc64_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC64_LINUX)
+vgpreload_exp_sgcheck_ppc64_linux_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_PPC64_LINUX) \
+ $(LIBREPLACEMALLOC_LDFLAGS_PPC64_LINUX)
+
+vgpreload_exp_sgcheck_ppc32_aix5_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_ppc32_aix5_so_CPPFLAGS = $(AM_CPPFLAGS_PPC32_AIX5)
+vgpreload_exp_sgcheck_ppc32_aix5_so_CFLAGS = $(AM_CFLAGS_PPC32_AIX5) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_ppc32_aix5_so_CCASFLAGS = $(AM_CCASFLAGS_PPC32_AIX5)
+vgpreload_exp_sgcheck_ppc32_aix5_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC32_AIX5)
+vgpreload_exp_sgcheck_ppc32_aix5_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_PPC32_AIX5) \
+ $(LIBREPLACEMALLOC_LDFLAGS_PPC32_AIX5)
+
+vgpreload_exp_sgcheck_ppc64_aix5_so_SOURCES = $(VGPRELOAD_EXP_SGCHECK_SOURCES_COMMON)
+vgpreload_exp_sgcheck_ppc64_aix5_so_CPPFLAGS = $(AM_CPPFLAGS_PPC64_AIX5)
+vgpreload_exp_sgcheck_ppc64_aix5_so_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_sgcheck_ppc64_aix5_so_CCASFLAGS = $(AM_CCASFLAGS_PPC64_AIX5)
+vgpreload_exp_sgcheck_ppc64_aix5_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC64_AIX5)
+vgpreload_exp_sgcheck_ppc64_aix5_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_PPC64_AIX5) \
+ $(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+
+
+
+EXP_SGCHECK_SOURCES_COMMON = sg_main.c
+
+exp_sgcheck_x86_linux_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_x86_linux_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
+exp_sgcheck_x86_linux_CFLAGS = $(AM_CFLAGS_X86_LINUX)
+exp_sgcheck_x86_linux_DEPENDENCIES = $(COREGRIND_LIBS_X86_LINUX)
+exp_sgcheck_x86_linux_LDADD = $(TOOL_LDADD_X86_LINUX)
+exp_sgcheck_x86_linux_LDFLAGS = $(TOOL_LDFLAGS_X86_LINUX)
+
+exp_sgcheck_amd64_linux_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_amd64_linux_CPPFLAGS = $(AM_CPPFLAGS_AMD64_LINUX)
+exp_sgcheck_amd64_linux_CFLAGS = $(AM_CFLAGS_AMD64_LINUX)
+exp_sgcheck_amd64_linux_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_LINUX)
+exp_sgcheck_amd64_linux_LDADD = $(TOOL_LDADD_AMD64_LINUX)
+exp_sgcheck_amd64_linux_LDFLAGS = $(TOOL_LDFLAGS_AMD64_LINUX)
+
+exp_sgcheck_ppc32_linux_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_ppc32_linux_CPPFLAGS = $(AM_CPPFLAGS_PPC32_LINUX)
+exp_sgcheck_ppc32_linux_CFLAGS = $(AM_CFLAGS_PPC32_LINUX)
+exp_sgcheck_ppc32_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_LINUX)
+exp_sgcheck_ppc32_linux_LDADD = $(TOOL_LDADD_PPC32_LINUX)
+exp_sgcheck_ppc32_linux_LDFLAGS = $(TOOL_LDFLAGS_PPC32_LINUX)
+
+exp_sgcheck_ppc64_linux_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_ppc64_linux_CPPFLAGS = $(AM_CPPFLAGS_PPC64_LINUX)
+exp_sgcheck_ppc64_linux_CFLAGS = $(AM_CFLAGS_PPC64_LINUX)
+exp_sgcheck_ppc64_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_LINUX)
+exp_sgcheck_ppc64_linux_LDADD = $(TOOL_LDADD_PPC64_LINUX)
+exp_sgcheck_ppc64_linux_LDFLAGS = $(TOOL_LDFLAGS_PPC64_LINUX)
+
+exp_sgcheck_ppc32_aix5_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_ppc32_aix5_CPPFLAGS = $(AM_CPPFLAGS_PPC32_AIX5)
+exp_sgcheck_ppc32_aix5_CFLAGS = $(AM_CFLAGS_PPC32_AIX5)
+exp_sgcheck_ppc32_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_AIX5)
+exp_sgcheck_ppc32_aix5_LDADD = $(TOOL_LDADD_PPC32_AIX5)
+exp_sgcheck_ppc32_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC32_AIX5)
+
+exp_sgcheck_ppc64_aix5_SOURCES = $(EXP_SGCHECK_SOURCES_COMMON)
+exp_sgcheck_ppc64_aix5_CPPFLAGS = $(AM_CPPFLAGS_PPC64_AIX5)
+exp_sgcheck_ppc64_aix5_CFLAGS = $(AM_CFLAGS_PPC64_AIX5)
+exp_sgcheck_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
+exp_sgcheck_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
+exp_sgcheck_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
Added: branches/SGCHECK/exp-sgcheck/docs/Makefile.am
===================================================================
Added: branches/SGCHECK/exp-sgcheck/sg_intercepts.c
===================================================================
--- branches/SGCHECK/exp-sgcheck/sg_intercepts.c (rev 0)
+++ branches/SGCHECK/exp-sgcheck/sg_intercepts.c 2008-08-19 11:20:35 UTC (rev 8528)
@@ -0,0 +1,164 @@
+
+/*--------------------------------------------------------------------*/
+/*--- sgcheck: a stack/global array overrun checker. ---*/
+/*--- sg_intercepts.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of SGcheck, a Valgrind tool for checking
+ overruns in stack and global arrays in programs.
+
+ Copyright (C) 2008-2008 OpenWorks Ltd
+ in...@op...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Nothing actually in here. However it appears this file is needed
+ to make malloc intercepting work. (jrs, 2 july 08 -- not sure about
+ that).
+*/
+
+#include "pub_tool_basics.h"
+#include "pub_tool_hashtable.h"
+#include "pub_tool_redir.h"
+#include "pub_tool_tooliface.h"
+#include "valgrind.h"
+
+
+/* The following intercepts are copied verbatim from
+ memcheck/mc_replace_strmem.c. */
+
+/* --------- Some handy Z-encoded names. --------- */
+
+/* --- Soname of the standard C library. --- */
+
+#if defined(VGO_linux)
+# define m_libc_soname libcZdsoZa // libc.so*
+#elif defined(VGP_ppc32_aix5)
+ /* AIX has both /usr/lib/libc.a and /usr/lib/libc_r.a. */
+# define m_libc_soname libcZaZdaZLshrZdoZR // libc*.a(shr.o)
+#elif defined(VGP_ppc64_aix5)
+# define m_libc_soname libcZaZdaZLshrZu64ZdoZR // libc*.a(shr_64.o)
+#else
+# error "Unknown platform"
+#endif
+
+/* --- Sonames for Linux ELF linkers. --- */
+
+#define m_ld_linux_so_2 ldZhlinuxZdsoZd2 // ld-linux.so.2
+#define m_ld_linux_x86_64_so_2 ldZhlinuxZhx86Zh64ZdsoZd2 // ld-linux-x86-64.so.2
+#define m_ld64_so_1 ld64ZdsoZd1 // ld64.so.1
+#define m_ld_so_1 ldZdsoZd1 // ld.so.1
+
+
+
+
+#define STRCMP(soname, fnname) \
+ int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( const char* s1, const char* s2 ); \
+ int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( const char* s1, const char* s2 ) \
+ { \
+ register unsigned char c1; \
+ register unsigned char c2; \
+ while (True) { \
+ c1 = *(unsigned char *)s1; \
+ c2 = *(unsigned char *)s2; \
+ if (c1 != c2) break; \
+ if (c1 == 0) break; \
+ s1++; s2++; \
+ } \
+ if ((unsigned char)c1 < (unsigned char)c2) return -1; \
+ if ((unsigned char)c1 > (unsigned char)c2) return 1; \
+ return 0; \
+ }
+
+STRCMP(m_libc_soname, strcmp)
+STRCMP(m_ld_linux_x86_64_so_2, strcmp)
+STRCMP(m_ld64_so_1, strcmp)
+
+
+// Note that this replacement often doesn't get used because gcc inlines
+// calls to strlen() with its own built-in version. This can be very
+// confusing if you aren't expecting it. Other small functions in this file
+// may also be inline by gcc.
+#define STRLEN(soname, fnname) \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
+ { \
+ SizeT i = 0; \
+ while (str[i] != 0) i++; \
+ return i; \
+ }
+
+STRLEN(m_libc_soname, strlen)
+STRLEN(m_ld_linux_so_2, strlen)
+STRLEN(m_ld_linux_x86_64_so_2, strlen)
+
+
+#define MEMCPY(soname, fnname) \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( void *dst, const void *src, SizeT sz ); \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( void *dest, const void *src, SizeT sz ) \
+ { \
+ const UChar* s = (const UChar*)src; \
+ UChar* d = (UChar*)dest; \
+ const UWord* sW = (const UWord*)src; \
+ UWord* dW = (UWord*)dest; \
+ const UWord al = sizeof(UWord)-1; \
+ \
+ if (0 == (((UWord)dW) & al) && 0 == (((UWord)sW) & al)) { \
+ while (sz >= 4 * sizeof(UWord)) { \
+ dW[0] = sW[0]; \
+ dW[1] = sW[1]; \
+ dW[2] = sW[2]; \
+ dW[3] = sW[3]; \
+ sz -= 4 * sizeof(UWord); \
+ dW += 4; \
+ sW += 4; \
+ } \
+ if (sz == 0) \
+ return dest; \
+ while (sz >= 1 * sizeof(UWord)) { \
+ dW[0] = sW[0]; \
+ sz -= 1 * sizeof(UWord); \
+ dW += 1; \
+ sW += 1; \
+ } \
+ if (sz == 0) \
+ return dest; \
+ s = (const UChar*)sW; \
+ d = (UChar*)dW; \
+ } \
+ \
+ while (sz--) \
+ *d++ = *s++; \
+ \
+ return dest; \
+ }
+
+MEMCPY(m_libc_soname, memcpy)
+MEMCPY(m_ld_so_1, memcpy) /* ld.so.1 */
+MEMCPY(m_ld64_so_1, memcpy) /* ld64.so.1 */
+
+
+/*--------------------------------------------------------------------*/
+/*--- sg_intercepts.c ---*/
+/*--------------------------------------------------------------------*/
Added: branches/SGCHECK/exp-sgcheck/sg_main.c
===================================================================
--- branches/SGCHECK/exp-sgcheck/sg_main.c (rev 0)
+++ branches/SGCHECK/exp-sgcheck/sg_main.c 2008-08-19 11:20:35 UTC (rev 8528)
@@ -0,0 +1,1908 @@
+
+/*--------------------------------------------------------------------*/
+/*--- sgcheck: a stack/global array overrun checker. ---*/
+/*--- sg_main.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of SGcheck, a Valgrind tool for checking
+ overruns in stack and global arrays in programs.
+
+ Copyright (C) 2008-2008 OpenWorks Ltd
+ in...@op...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_tool_basics.h"
+
+#include "pub_tool_libcbase.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_libcprint.h"
+
+#include "pub_tool_tooliface.h"
+
+#include "pub_tool_wordfm.h"
+#include "pub_tool_xarray.h"
+#include "pub_tool_threadstate.h"
+#include "pub_tool_mallocfree.h"
+#include "pub_tool_machine.h"
+#include "pub_tool_options.h"
+#include "pub_tool_debuginfo.h"
+#include "pub_tool_replacemalloc.h"
+
+
+static void preen_Invars ( Addr a, SizeT len, Bool isHeap ); /*fwds*/
+
+
+//////////////////////////////////////////////////////////////
+// //
+// Basic Stuff //
+// //
+//////////////////////////////////////////////////////////////
+
+static inline Bool is_sane_TId ( ThreadId tid )
+{
+ return tid >= 0 && tid < VG_N_THREADS
+ && tid != VG_INVALID_THREADID;
+}
+
+static void* pc_malloc ( SizeT n ) {
+ void* p;
+ tl_assert(n > 0);
+ p = VG_(malloc)( n );
+ tl_assert(p);
+ return p;
+}
+
+static void pc_free ( void* p ) {
+ tl_assert(p);
+ VG_(free)(p);
+}
+
+
+//////////////////////////////////////////////////////////////
+// //
+// Management of StackBlocks //
+// //
+//////////////////////////////////////////////////////////////
+
+/* We maintain a set of XArray* of StackBlocks. These are never
+ freed. When a new StackBlock vector is acquired from
+ VG_(di_get_local_blocks_at_ip), we compare it to the existing set.
+ If not present, it is added. If present, the just-acquired one is
+ freed and the copy used.
+
+ This simplifies storage management elsewhere. It allows us to
+ assume that a pointer to an XArray* of StackBlock is valid forever.
+ It also means there are no duplicates anywhere, which could be
+ important from a space point of view for programs that generate a
+ lot of translations, or where translations are frequently discarded
+ and re-made.
+
+ Note that we normalise the arrays by sorting the elements according
+ to an arbitrary total order, so as to avoid the situation that two
+ vectors describe the same set of variables but are not structurally
+ identical. */
+
+static inline Bool StackBlock__sane ( StackBlock* fb ) {
+ if (fb->name[ sizeof(fb->name)-1 ] != 0)
+ return False;
+ if (fb->spRel != False && fb->spRel != True)
+ return False;
+ if (fb->isVec != False && fb->isVec != True)
+ return False;
+ return True;
+}
+
+static Int StackBlock__cmp ( StackBlock* fb1, StackBlock* fb2 ) {
+ Int r;
+ tl_assert(StackBlock__sane(fb1));
+ tl_assert(StackBlock__sane(fb2));
+ /* Hopefully the .base test hits most of the time. For the blocks
+ associated with any particular instruction, if the .base values
+ are the same then probably it doesn't make sense for the other
+ fields to be different. But this is supposed to be a completely
+ general structural total order, so we have to compare everything
+ anyway. */
+ if (fb1->base < fb2->base) return -1;
+ if (fb1->base > fb2->base) return 1;
+ /* compare sizes */
+ if (fb1->szB < fb2->szB) return -1;
+ if (fb1->szB > fb2->szB) return 1;
+ /* compare sp/fp flag */
+ if (fb1->spRel < fb2->spRel) return -1;
+ if (fb1->spRel > fb2->spRel) return 1;
+ /* compare is/is-not array-typed flag */
+ if (fb1->isVec < fb2->isVec) return -1;
+ if (fb1->isVec > fb2->isVec) return 1;
+ /* compare the name */
+ r = VG_(strcmp)(fb1->name, fb2->name);
+ return r;
+}
+
+/* Generate an arbitrary total ordering on vectors of StackBlocks. */
+static Word StackBlocks__cmp ( XArray* fb1s, XArray* fb2s ) {
+ Int r;
+ Word i;
+ Word n1 = VG_(sizeXA)( fb1s );
+ Word n2 = VG_(sizeXA)( fb2s );
+ Word n = n1 > n2 ? n1 : n2; /* max(n1,n2) */
+ for (i = 0; i < n; i++) {
+ StackBlock *fb1, *fb2;
+ if (i >= n1) {
+ /* fb1s ends first, and all previous entries identical. */
+ tl_assert(i < n2);
+ return -1;
+ }
+ if (i >= n2) {
+ /* fb2s ends first, and all previous entries identical. */
+ tl_assert(i < n1);
+ return 1;
+ }
+ tl_assert(i < n1 && i < n2);
+ fb1 = VG_(indexXA)( fb1s, i );
+ fb2 = VG_(indexXA)( fb2s, i );
+ r = StackBlock__cmp( fb1, fb2 );
+ if (r != 0) return r;
+ }
+ tl_assert(n1 == n2);
+ return 0;
+}
+
+
+/* ---------- The StackBlock vector cache ---------- */
+
+static WordFM* /* XArray* of StackBlock -> nothing */
+ frameBlocks_set = NULL;
+
+static void init_StackBlocks_set ( void )
+{
+ tl_assert(!frameBlocks_set);
+ frameBlocks_set = VG_(newFM)( pc_malloc, pc_free,
+ (Word(*)(UWord,UWord))StackBlocks__cmp );
+ tl_assert(frameBlocks_set);
+}
+
+/* Find the given StackBlock-vector in our collection thereof. If
+ found, deallocate the supplied one, and return the address of the
+ copy. If not found, add the supplied one to our collection and
+ return its address. */
+static XArray* /* of StackBlock */
+ StackBlocks__find_and_dealloc__or_add
+ ( XArray* /* of StackBlock */ orig )
+{
+ UWord key, val;
+
+ /* First, normalise, as per comments above. */
+ VG_(setCmpFnXA)( orig, (Int(*)(void*,void*))StackBlock__cmp );
+ VG_(sortXA)( orig );
+
+ /* Now, do we have it already? */
+ if (VG_(lookupFM)( frameBlocks_set, &key, &val, (UWord)orig )) {
+ /* yes */
+ tl_assert(val == 0);
+ tl_assert(key != (UWord)orig);
+ VG_(deleteXA)(orig);
+ return (XArray*)key;
+ } else {
+ /* no */
+ VG_(addToFM)( frameBlocks_set, (UWord)orig, 0 );
+ return orig;
+ }
+}
+
+/* Top level function for getting the StackBlock vector for a given
+ instruction. */
+
+static XArray* /* of StackBlock */ get_StackBlocks_for_IP ( Addr ip )
+{
+ XArray* blocks = VG_(di_get_stack_blocks_at_ip)( ip, False/*!arrays only*/ );
+ tl_assert(blocks);
+ return StackBlocks__find_and_dealloc__or_add( blocks );
+}
+
+
+//////////////////////////////////////////////////////////////
+// //
+// The Global Block Interval Tree //
+// //
+//////////////////////////////////////////////////////////////
+
+/* This tree holds all the currently known-about globals. We must
+ modify it at each mmap that results in debuginfo being read, and at
+ each munmap, as the latter will cause globals to disappear. At
+ each munmap, we must also prune the Invars, since munmaps may cause
+ GlobalBlocks to disappear, and so the Invars may no longer mention
+ them. */
+
+/* Implement an interval tree, containing GlobalBlocks. The blocks
+ must all be non-zero sized and may not overlap. The access
+ functions maintain that invariant.
+
+ Storage management: GlobalBlocks in the tree are copies of ones
+ presented as args to add_GlobalBlock. The originals are never
+ added to the tree. del_GlobalBlocks_in_range frees up the storage
+ allocated by add_GlobalBlock. */
+
+/* The tree */
+static WordFM* globals = NULL; /* WordFM GlobalBlock* void */
+
+static Word cmp_intervals_GlobalBlock ( GlobalBlock* gb1, GlobalBlock* gb2 )
+{
+ tl_assert(gb1 && gb1->szB > 0);
+ tl_assert(gb2 && gb2->szB > 0);
+ if (gb1->addr + gb1->szB <= gb2->addr) return -1;
+ if (gb2->addr + gb2->szB <= gb1->addr) return 1;
+ return 0;
+}
+
+static void init_globals ( void )
+{
+ tl_assert(!globals);
+ globals = VG_(newFM)( pc_malloc, pc_free,
+ (Word(*)(UWord,UWord))cmp_intervals_GlobalBlock );
+ tl_assert(globals);
+}
+
+
+/* Find the block containing 'a', if possible. Returned pointer is
+ only transiently valid; it will become invalid at the next global
+ mapping or unmapping operation. */
+static GlobalBlock* find_GlobalBlock_containing ( Addr a )
+{
+ UWord oldK, oldV;
+ GlobalBlock key;
+ key.addr = a;
+ key.szB = 1;
+ if (VG_(lookupFM)( globals, &oldK, &oldV, (UWord)&key )) {
+ GlobalBlock* res = (GlobalBlock*)oldK;
+ tl_assert(oldV == 0);
+ tl_assert(res->szB > 0);
+ tl_assert(res->addr <= a && a < res->addr + res->szB);
+ return res;
+ } else {
+ return NULL;
+ }
+}
+
+
+/* Add a block to the collection. Presented block is not stored
+ directly; instead a copy is made and stored. If the block overlaps
+ an existing block (it should not, but we need to be robust to such
+ eventualities) it is merged with existing block(s), so as to
+ preserve the no-overlap property of the tree as a whole. */
+static void add_GlobalBlock ( GlobalBlock* gbOrig )
+{
+ UWord keyW, valW;
+ GlobalBlock* gb;
+ tl_assert(gbOrig && gbOrig->szB > 0);
+ gb = pc_malloc( sizeof(GlobalBlock) );
+ *gb = *gbOrig;
+
+ /* Dealing with overlaps. One possibility is to look up the entire
+ interval to be added. If we get something back, it overlaps an
+ existing interval; then delete the existing interval, merge it
+ into the one to be added, and repeat, until the to-be added
+ interval really doesn't intersect any existing interval. */
+
+ while (VG_(lookupFM)( globals, &keyW, &valW, (UWord)gb )) {
+ tl_assert(valW == 0);
+ /* keyW is the overlapping key. Pull it out of the tree, merge
+ into 'gb', free keyW, complain to the user, repeat. */
+ tl_assert(0);
+ }
+
+ VG_(addToFM)(globals, (UWord)gb, (UWord)0);
+}
+
+
+/* Remove all blocks from the tree intersecting [a,a+len), and release
+ associated storage. One way to do it is to simply look up the
+ interval, and if something comes back, delete it on the basis that
+ it must intersect the interval. Keep doing this until the lookup
+ finds nothing. Returns a Bool indicating whether any blocks
+ did actually intersect the range. */
+static Bool del_GlobalBlocks_in_range ( Addr a, SizeT len )
+{
+ UWord oldK, oldV;
+ GlobalBlock key;
+ Bool foundAny = False;
+
+ tl_assert(len > 0);
+ key.addr = a;
+ key.szB = len;
+ while (VG_(delFromFM)( globals, &oldK, &oldV, (UWord)&key )) {
+ GlobalBlock* old;
+ tl_assert(oldV == 0);
+ old = (GlobalBlock*)oldK;
+ /* 'old' will be removed. Preen the Invars now? */
+ pc_free(old);
+ foundAny = True;
+ }
+ return foundAny;
+}
+
+
+//////////////////////////////////////////////////////////////
+
+static void acquire_globals ( ULong di_handle )
+{
+ Word n, i;
+ XArray* /* of GlobalBlock */ gbs;
+
+ if (0) VG_(printf)("ACQUIRE GLOBALS %llu\n", di_handle );
+ gbs = VG_(di_get_global_blocks_from_dihandle)
+ (di_handle, False/*!arrays only*/);
+ if (0) VG_(printf)(" GOT %ld globals\n", VG_(sizeXA)( gbs ));
+
+ n = VG_(sizeXA)( gbs );
+ for (i = 0; i < n; i++) {
+ GlobalBlock* gb = VG_(indexXA)( gbs, i );
+ VG_(printf)(" new Global size %2lu at %#lx: %s %s\n",
+ gb->szB, gb->addr, gb->soname, gb->name );
+ tl_assert(gb->szB > 0);
+ /* Add each global to the map. We can present them
+ indiscriminately to add_GlobalBlock, since that adds copies
+ of presented blocks, not the original. This is important
+ because we are just about to delete the XArray in which we
+ received these GlobalBlocks. */
+ add_GlobalBlock( gb );
+ }
+
+ VG_(deleteXA)( gbs );
+}
+
+
+/* We only intercept these two because we need to see any di_handles
+ that might arise from the mappings/allocations. */
+static void sg_new_mem_mmap( Addr a, SizeT len,
+ Bool rr, Bool ww, Bool xx, ULong di_handle )
+{
+ if (di_handle > 0)
+ acquire_globals(di_handle);
+}
+static void sg_new_mem_startup( Addr a, SizeT len,
+ Bool rr, Bool ww, Bool xx, ULong di_handle )
+{
+ if (di_handle > 0)
+ acquire_globals(di_handle);
+}
+static void sg_die_mem_munmap ( Addr a, SizeT len )
+{
+ Bool debug = 0||False;
+ Bool overlap = False;
+ if (debug) VG_(printf)("MUNMAP %#lx %lu\n", a, len );
+ if (len == 0)
+ return;
+
+ overlap = del_GlobalBlocks_in_range(a, len);
+ if (!overlap)
+ return;
+
+ /* Ok, the range contained some blocks. Therefore we'll need to
+ visit all the Invars in all the thread shadow stacks, and
+ convert all Inv_Global{S,V} entries that intersect [a,a+len) to
+ Inv_Unknown. */
+ tl_assert(len > 0);
+ preen_Invars( a, len, False/*!isHeap*/ );
+}
+
+
+//////////////////////////////////////////////////////////////
+// //
+// The Heap Block Interval Tree //
+// //
+//////////////////////////////////////////////////////////////
+
+/* This tree holds all the currently known-about heap blocks. We must
+ modify it at each malloc/free, and prune the Invars when freeing
+ blocks (since they disappear, the Invars may no longer mention
+ them). */
+
+/* Implement an interval tree, containing HeapBlocks. The blocks must
+ all be non-zero sized and may not overlap, although if they do
+ overlap that must constitute a bug in our malloc/free
+ implementation, and so we might as well just assert.
+
+ There's a nasty kludge. In fact we must be able to deal with zero
+ sized blocks, since alloc_mem_heap/free_mem_heap/pc_replace_malloc
+ use the blocks stored to keep track of what blocks the client has
+ allocated, so there's no avoiding the requirement of having one
+ block in the tree for each client allocated block, even for
+ zero-sized client blocks.
+
+ The kludge is: have two size fields. One is the real size
+ (.realSzB) and can be zero. The other (.fakeSzB) is used, along
+ with .addr to provide the ordering induced by
+ cmp_intervals_HeapBlock. .fakeSzB is the same as .realSzB except
+ in the single case where .realSzB is zero, in which case .fakeSzB
+ is 1. This works because the allocator won't allocate two zero
+ sized blocks at the same location (ANSI C disallows this) and so,
+ from an ordering point of view, it's safe treat zero sized blocks
+ as blocks of size 1. However, we need to keep the real un-kludged
+ size around too (as .realSzB), so that
+ alloc_mem_heap/free_mem_heap/pc_replace_malloc and also
+ classify_block have correct information.
+
+ Storage management: HeapBlocks in the tree are copies of ones
+ presented as args to add_HeapBlock. The originals are never
+ added to the tree. del_HeapBlocks_in_range frees up the storage
+ allocated by add_GlobalBlock. */
+
+typedef
+ struct {
+ Addr addr;
+ SizeT fakeSzB;
+ SizeT realSzB;
+ }
+ HeapBlock;
+
+/* the tree */
+static WordFM* heap = NULL; /* WordFM HeapBlock* void */
+
+static Word cmp_intervals_HeapBlock ( HeapBlock* hb1, HeapBlock* hb2 )
+{
+ tl_assert(hb1);
+ tl_assert(hb2);
+ tl_assert(hb1->fakeSzB > 0);
+ tl_assert(hb2->fakeSzB > 0);
+ if (hb1->addr + hb1->fakeSzB <= hb2->addr) return -1;
+ if (hb2->addr + hb2->fakeSzB <= hb1->addr) return 1;
+ return 0;
+}
+
+
+static void init_heap ( void )
+{
+ tl_assert(!heap);
+ heap = VG_(newFM)( pc_malloc, pc_free,
+ (Word(*)(UWord,UWord))cmp_intervals_HeapBlock );
+ tl_assert(heap);
+}
+
+
+/* Find the heap block containing 'a', if possible. Returned pointer
+ is only transiently valid; it will become invalid at the next
+ client malloc or free operation. */
+static HeapBlock* find_HeapBlock_containing ( Addr a )
+{
+ UWord oldK, oldV;
+ HeapBlock key;
+ key.addr = a;
+ key.fakeSzB = 1;
+ key.realSzB = 0; /* unused, but initialise it anyway */
+ if (VG_(lookupFM)( heap, &oldK, &oldV, (UWord)&key )) {
+ HeapBlock* res = (HeapBlock*)oldK;
+ tl_assert(oldV == 0);
+ tl_assert(res->fakeSzB > 0);
+ tl_assert(res->addr <= a && a < res->addr + res->fakeSzB);
+ /* Now, just one more thing. If the real size is in fact zero
+ then 'a' can't fall within it. No matter what 'a' is. Hence: */
+ if (res->realSzB == 0) {
+ tl_assert(res->fakeSzB == 1);
+ return NULL;
+ }
+ /* Normal case. */
+ return res;
+ } else {
+ return NULL;
+ }
+}
+
+
+/* Add a block to the collection. If the block overlaps an existing
+ block (it should not, but we need to be robust to such
+ eventualities) we simply assert, as that is probably a result of a
+ bug in our malloc implementation. (although could be due to buggy
+ custom allocators?) In any case we must either assert or somehow
+ (as per GlobalBlocks) avoid overlap, so as to preserve the
+ no-overlap property of the tree as a whole. */
+static void add_HeapBlock ( Addr addr, SizeT realSzB )
+{
+ UWord keyW, valW;
+ HeapBlock* hb;
+
+ SizeT fakeSzB = realSzB == 0 ? 1 : realSzB;
+ tl_assert(fakeSzB > 0);
+
+ tl_assert(addr);
+ hb = pc_malloc( sizeof(HeapBlock) );
+ hb->addr = addr;
+ hb->fakeSzB = fakeSzB;
+ hb->realSzB = realSzB;
+ /* Check there's no overlap happening. */
+ while (VG_(lookupFM)( heap, &keyW, &valW, (UWord)hb )) {
+ tl_assert(valW == 0);
+ /* keyW is the overlapping HeapBlock*. Need to handle this
+ case, as per comment above. */
+ tl_assert(0);
+ }
+
+ VG_(addToFM)(heap, (UWord)hb, (UWord)0);
+}
+
+
+/* Delete a heap block at guest address 'addr' from the tree. Ignore
+ if there is no block beginning exactly at 'addr' (means the guest
+ is handing invalid pointers to free() et al). Returns the True if
+ found, in which case the block's size is written to *szB. The
+ shadow block (HeapBlock) is freed, but the payload (what .addr
+ points at) are not. */
+static Bool del_HeapBlock_at ( SizeT* szB, Addr addr )
+{
+ Bool b;
+ UWord oldK, oldV;
+ HeapBlock key, *hb;
+
+ hb = find_HeapBlock_containing(addr);
+ if (!hb) return False;
+ if (hb->addr != addr) return False;
+
+ key.addr = addr;
+ key.fakeSzB = 1;
+ key.realSzB = 0; /* unused, but initialise it anyway */
+ b = VG_(delFromFM)( heap, &oldK, &oldV, (UWord)&key );
+ tl_assert(b); /* we just looked it up, so deletion must succeed */
+ tl_assert(oldV == 0);
+
+ hb = (HeapBlock*)oldK;
+ tl_assert(hb);
+ tl_assert(hb->addr == addr);
+
+ *szB = hb->realSzB;
+ pc_free(hb);
+ return True;
+}
+
+
+//////////////////////////////////////////////////////////////
+static
+void* alloc_mem_heap ( ThreadId tid,
+ SizeT size, SizeT alignment, Bool is_zeroed )
+{
+ Addr p;
+ if ( ((SSizeT)size) < 0)
+ return NULL;
+ p = (Addr)VG_(cli_malloc)(alignment, size);
+ if (p == 0)
+ return NULL;
+ if (is_zeroed)
+ VG_(memset)((void*)p, 0, size);
+ add_HeapBlock( p, size );
+ return (void*)p;
+}
+
+static void free_mem_heap ( ThreadId tid, Addr p )
+{
+ SizeT old_size = 0;
+ Bool found = del_HeapBlock_at( &old_size, p );
+ if (found) {
+ VG_(cli_free)( (void*)p );
+ if (old_size > 0)
+ preen_Invars( p, old_size, True/*isHeap*/ );
+ }
+}
+
+static void* pc_replace_malloc ( ThreadId tid, SizeT n ) {
+ return alloc_mem_heap ( tid, n, VG_(clo_alignment),
+ /*is_zeroed*/False );
+}
+
+static void* pc_replace___builtin_new ( ThreadId tid, SizeT n ) {
+ return alloc_mem_heap ( tid, n, VG_(clo_alignment),
+ /*is_zeroed*/False );
+}
+
+static void* pc_replace___builtin_vec_new ( ThreadId tid, SizeT n ) {
+ return alloc_mem_heap ( tid, n, VG_(clo_alignment),
+ /*is_zeroed*/False );
+}
+
+static void* pc_replace_memalign ( ThreadId tid, SizeT align, SizeT n ) {
+ return alloc_mem_heap ( tid, n, align,
+ /*is_zeroed*/False );
+}
+
+static void* pc_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
+ return alloc_mem_heap ( tid, nmemb*size1, VG_(clo_alignment),
+ /*is_zeroed*/True );
+}
+
+static void pc_replace_free ( ThreadId tid, void* p ) {
+ free_mem_heap(tid, (Addr)p);
+}
+
+static void pc_replace___builtin_delete ( ThreadId tid, void* p ) {
+ free_mem_heap(tid, (Addr)p);
+}
+
+static void pc_replace___builtin_vec_delete ( ThreadId tid, void* p ) {
+ free_mem_heap(tid, (Addr)p);
+}
+
+static void* pc_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size )
+{
+ Addr p_new;
+
+ /* First try and find the block. */
+ SizeT old_size = 0;
+ Bool found = del_HeapBlock_at( &old_size, (Addr)p_old );
+
+ if (!found)
+ return NULL;
+
+ if (old_size > 0)
+ preen_Invars( (Addr)p_old, old_size, True/*isHeap*/ );
+
+ if (new_size <= old_size) {
+ /* new size is smaller: allocate, copy from old to new */
+ p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
+ VG_(memcpy)((void*)p_new, p_old, new_size);
+ } else {
+ /* new size is bigger: allocate, copy from old to new */
+ p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
+ VG_(memcpy)((void*)p_new, p_old, old_size);
+ }
+
+ VG_(cli_free)( (void*)p_old );
+ add_HeapBlock( p_new, new_size );
+ return (void*)p_new;
+}
+
+
+//////////////////////////////////////////////////////////////
+// //
+// Invar //
+// //
+//////////////////////////////////////////////////////////////
+
+/* An invariant, as resulting from watching the destination of a
+ memory referencing instruction. Initially is Inv_Unset until the
+ instruction makes a first access. */
+
+typedef
+ enum {
+ Inv_Unset=1, /* not established yet */
+ Inv_Unknown, /* unknown location */
+ Inv_StackS, Inv_StackV, /* scalar/vector stack block */
+ Inv_GlobalS, Inv_GlobalV, /* scalar/vector global block */
+ Inv_Heap /* a block in the heap */
+ }
+ InvarTag;
+
+typedef
+ struct {
+ InvarTag tag;
+ union {
+ struct {
+ } Unset;
+ struct {
+ } Unknown;
+ struct {
+ /* EQ */ UWord framesBack;
+ /* EQ */ UWord fbIndex;
+ /* EXPO */ HChar name[16]; /* asciiz */
+ /* ReVal */ Addr start;
+ /* ReVal */ SizeT len;
+ } Stack;
+ struct {
+ /* EQ */ HChar name[16]; /* asciiz */
+ /* EQ */ HChar soname[16]; /* asciiz */
+ /* ReVal */ Addr start;
+ /* ReVal */ SizeT len;
+ } Global;
+ struct {
+ /* EQ, ReVal */ Addr start;
+ /* ReVal */ SizeT len;
+ } Heap;
+ }
+ Inv;
+ }
+ Invar;
+
+/* Compare two Invars for equality, based on the EQ fields in the
+ declaration above. */
+static Bool eq_Invar ( Invar* i1, Invar* i2 )
+{
+ tl_assert(i1->tag != Inv_Unset);
+ tl_assert(i2->tag != Inv_Unset);
+ if (i1->tag != i2->tag)
+ return False;
+ switch (i1->tag) {
+ case Inv_Unknown:
+ return True;
+ case Inv_StackS:
+ case Inv_StackV:
+ return i1->Inv.Stack.framesBack == i2->Inv.Stack.framesBack
+ && i1->Inv.Stack.fbIndex == i2->Inv.Stack.fbIndex;
+ case Inv_GlobalS:
+ case Inv_GlobalV:
+ tl_assert(i1->Inv.Global.name[
+ sizeof(i1->Inv.Global.name)-1 ] == 0);
+ tl_assert(i2->Inv.Global.name[
+ sizeof(i2->Inv.Global.name)-1 ] == 0);
+ tl_assert(i1->Inv.Global.soname[
+ sizeof(i1->Inv.Global.soname)-1 ] == 0);
+ tl_assert(i2->Inv.Global.soname[
+ sizeof(i2->Inv.Global.soname)-1 ] == 0);
+ return
+ 0==VG_(strcmp)(i1->Inv.Global.name, i2->Inv.Global.name)
+ && 0==VG_(strcmp)(i1->Inv.Global.soname, i2->Inv.Global.soname);
+ case Inv_Heap:
+ return i1->Inv.Heap.start == i2->Inv.Heap.start
+ && i1->Inv.Heap.len == i2->Inv.Heap.len;
+ default:
+ tl_assert(0);
+ }
+ /*NOTREACHED*/
+ tl_assert(0);
+}
+
+/* Print selected parts of an Invar, suitable for use in error
+ messages. */
+static void show_Invar( HChar* buf, Word nBuf, Invar* inv )
+{
+ HChar* str;
+ tl_assert(nBuf >= 128);
+ buf[0] = 0;
+ switch (inv->tag) {
+ case Inv_Unknown:
+ VG_(sprintf)(buf, "%s", "unknown");
+ break;
+ case Inv_StackS:
+ case Inv_StackV:
+ tl_assert(inv->Inv.Stack.name[sizeof(inv->Inv.Stack.name)-1] == 0);
+ str = inv->tag == Inv_StackS ? "non-array" : "array";
+ if (inv->Inv.Stack.framesBack == 0) {
+ VG_(sprintf)(buf, "stack %s \"%s\" in this frame",
+ str, inv->Inv.Stack.name );
+ } else {
+ VG_(sprintf)(buf, "stack %s \"%s\" in frame %lu back from here",
+ str, inv->Inv.Stack.name,
+ inv->Inv.Stack.framesBack );
+ }
+ break;
+ case Inv_GlobalS:
+ case Inv_GlobalV:
+ str = inv->tag == Inv_GlobalS ? "non-array" : "array";
+ VG_(sprintf)(buf, "global %s \"%s\" in object with soname \"%s\"",
+ str, inv->Inv.Global.name, inv->Inv.Global.soname );
+ break;
+ case Inv_Heap:
+ VG_(sprintf)(buf, "%s", "heap block");
+ break;
+ case Inv_Unset:
+ VG_(sprintf)(buf, "%s", "Unset!");
+ break;
+ default:
+ tl_assert(0);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////
+// //
+// StackFrame //
+// //
+//////////////////////////////////////////////////////////////
+
+static ULong stats__total_accesses = 0;
+static ULong stats__reval_Stack = 0;
+static ULong stats__reval_Global = 0;
+static ULong stats__reval_Heap = 0;
+static ULong stats__classify_Stack = 0;
+static ULong stats__classify_Global = 0;
+static ULong stats__classify_Heap = 0;
+static ULong stats__classify_Unknown = 0;
+static ULong stats__Invars_preened = 0;
+static ULong stats__Invars_changed = 0;
+
+/* A dynamic instance of an instruction */
+typedef
+ struct {
+ /* IMMUTABLE */
+ Addr insn_addr; /* NB! zero means 'not in use' */
+ XArray* blocks; /* XArray* of StackBlock */
+ /* MUTABLE */
+ Invar invar;
+ }
+ IInstance;
+
+
+typedef
+ struct {
+ /* The sp when the frame was created, so we know when to get rid
+ of it. */
+ Addr creation_sp;
+ /* Information for each memory referencing instruction, for this
+ instantiation of the function. The iinstances array is
+ operated as a simple linear-probe hash table, which is
+ dynamically expanded as necessary. Once critical thing is
+ that an IInstance with a .insn_addr of zero is interpreted to
+ mean that hash table slot is unused. This means we can't
+ store an IInstance for address zero. */
+ IInstance* htab;
+ UWord htab_size; /* size of hash table, MAY ONLY BE A POWER OF 2 */
+ UWord htab_used; /* number of hash table slots currently in use */
+ /* If this frame is currently making a call, then the following
+ are relevant. */
+ Addr sp_at_call;
+ Addr fp_at_call;
+ XArray* /* of StackBlock */ blocks_at_call;
+ }
+ StackFrame;
+
+
+/* ShadowStack == XArray of StackFrame */
+
+
+static XArray* shadowStacks[VG_N_THREADS];
+
+static void shadowStacks_init ( void )
+{
+ Int i;
+ for (i = 0; i < VG_N_THREADS; i++) {
+ shadowStacks[i] = NULL;
+ }
+}
+
+
+/* Move this somewhere else? */
+/* Visit all Invars in the entire system. If 'isHeap' is True, change
+ all Inv_Heap Invars that intersect [a,a+len) to Inv_Unknown. If
+ 'isHeap' is False, do the same but to the Inv_Global{S,V} Invars
+ instead. */
+inline
+static Bool rangesOverlap ( Addr a1, SizeT n1, Addr a2, SizeT n2 ) {
+ tl_assert(n1 > 0 && n2 > 0);
+ if (a1 + n1 < a2) return False;
+ if (a2 + n2 < a1) return False;
+ return True;
+}
+
+__attribute__((noinline))
+static void preen_Invar ( Invar* inv, Addr a, SizeT len, Bool isHeap )
+{
+ stats__Invars_preened++;
+ tl_assert(len > 0);
+ tl_assert(inv);
+ switch (inv->tag) {
+ case Inv_Heap:
+ tl_assert(inv->Inv.Heap.len > 0);
+ if (isHeap && rangesOverlap(a, len, inv->Inv.Heap.start,
+ inv->Inv.Heap.len)) {
+ inv->tag = Inv_Unknown;
+ stats__Invars_changed++;
+ }
+ break;
+ case Inv_GlobalS:
+ case Inv_GlobalV:
+ tl_assert(inv->Inv.Global.len > 0);
+ if ((!isHeap)
+ && rangesOverlap(a, len, inv->Inv.Global.start,
+ inv->Inv.Global.len)) {
+ inv->tag = Inv_Unknown;
+ stats__Invars_changed++;
+ }
+ break;
+ case Inv_StackS:
+ case Inv_StackV:
+ case Inv_Unknown:
+ break;
+ default: tl_assert(0);
+ }
+}
+
+__attribute__((noinline))
+static void preen_Invars ( Addr a, SizeT len, Bool isHeap )
+{
+ Int i;
+ Word ixFrames, nFrames;
+ UWord u;
+ XArray* stack; /* XArray* of StackFrame */
+ StackFrame* frame;
+ tl_assert(len > 0);
+ for (i = 0; i < VG_N_THREADS; i++) {
+ stack = shadowStacks[i];
+ if (!stack)
+ continue;
+ nFrames = VG_(sizeXA)( stack );
+ for (ixFrames = 0; ixFrames < nFrames; ixFrames++) {
+ UWord xx = 0; /* sanity check only; count of used htab entries */
+ frame = VG_(indexXA)( stack, ixFrames );
+ tl_assert(frame->htab);
+ for (u = 0; u < frame->htab_size; u++) {
+ IInstance* ii = &frame->htab[u];
+ if (ii->insn_addr == 0)
+ continue; /* not in use */
+ preen_Invar( &ii->invar, a, len, isHeap );
+ xx++;
+ }
+ tl_assert(xx == frame->htab_used);
+ }
+ }
+}
+
+
+__attribute__((noinline))
+static void initialise_hash_table ( StackFrame* sf )
+{
+ UWord i;
+ sf->htab_size = 4; /* initial hash table size */
+ sf->htab = pc_malloc(sf->htab_size * sizeof(IInstance));
+ tl_assert(sf->htab);
+ sf->htab_used = 0;
+ for (i = 0; i < sf->htab_size; i++)
+ sf->htab[i].insn_addr = 0; /* NOT IN USE */
+}
+
+
+__attribute__((noinline))
+static void resize_hash_table ( StackFrame* sf )
+{
+ UWord i, j, ix, old_size, new_size;
+ IInstance *old_htab, *new_htab, *old;
+
+ tl_assert(sf && sf->htab);
+ old_size = sf->htab_size;
+ new_size = 2 * old_size;
+ old_htab = sf->htab;
+ new_htab = pc_malloc( new_size * sizeof(IInstance) );
+ for (i = 0; i < new_size; i++) {
+ new_htab[i].insn_addr = 0; /* NOT IN USE */
+ }
+ for (i = 0; i < old_size; i++) {
+ old = &old_htab[i];
+ if (old->insn_addr == 0 /* NOT IN USE */)
+ continue;
+ ix = (old->insn_addr >> 0) & (new_size - 1);
+ /* find out where to put this, in the new table */
+ j = new_size;
+ while (1) {
+ if (new_htab[ix].insn_addr == 0)
+ break;
+ /* This can't ever happen, because it would mean the new
+ table is full; that isn't allowed -- even the old table is
+ only allowed to become half full. */
+ tl_assert(j > 0);
+ j--;
+ ix++; if (ix == new_size) ix = 0;
+ }
+ /* copy the old entry to this location */
+ tl_assert(ix < new_size);
+ tl_assert(new_htab[ix].insn_addr == 0);
+ new_htab[ix] = *old;
+ tl_assert(new_htab[ix].insn_addr != 0);
+ }
+ /* all entries copied; free old table. */
+ pc_free(old_htab);
+ sf->htab = new_htab;
+ sf->htab_size = new_size;
+ /* check sf->htab_used is correct. Optional and a bit expensive
+ but anyway: */
+ j = 0;
+ for (i = 0; i < new_size; i++) {
+ if (new_htab[i].insn_addr != 0) {
+ j++;
+ }
+ }
+ tl_assert(j == sf->htab_used);
+ if (0) VG_(printf)("resized tab for SF %p to %lu\n", sf, new_size);
+}
+
+
+__attribute__((noinline))
+static IInstance* find_or_create_IInstance (
+ StackFrame* sf,
+ Addr ip,
+ XArray* /* StackBlock */ ip_frameblocks
+ )
+{
+ UWord i, ix;
+ start_over:
+ tl_assert(sf);
+ tl_assert(sf->htab);
+
+ if (0) VG_(printf)("XXX ip %#lx size %lu used %lu\n",
+ ip, sf->htab_size, sf->htab_used);
+ tl_assert(2 * sf->htab_used <= sf->htab_size);
+
+ ix = (ip >> 0) & (sf->htab_size - 1);
+ i = sf->htab_size;
+ while (1) {
+ if (sf->htab[ix].insn_addr == ip)
+ return &sf->htab[ix];
+ if (sf->htab[ix].insn_addr == 0)
+ break;
+ /* If i ever gets to zero and we have found neither what we're
+ looking for nor an empty slot, the table must be full. Which
+ isn't possible -- we monitor the load factor to ensure it
+ doesn't get above say 50%; if that ever does happen the table
+ is resized. */
+ tl_assert(i > 0);
+ i--;
+ ix++;
+ if (ix == sf->htab_size) ix = 0;
+ }
+
+ /* So now we've found a free slot at ix, and we can use that.
+ Except, first check if we need to resize the table. If so,
+ resize it, and start all over again. */
+ tl_assert(sf->htab[ix].insn_addr == 0);
+ if (2 * sf->htab_used >= 1 * sf->htab_size) {
+ resize_hash_table(sf);
+ goto start_over;
+ }
+
+ /* Add a new record in this slot. */
+ tl_assert(ip != 0); /* CAN'T REPRESENT THIS */
+ sf->htab[ix].insn_addr = ip;
+ sf->htab[ix].blocks = ip_frameblocks;
+ sf->htab[ix].invar.tag = Inv_Unset;
+ sf->htab_used++;
+ return &sf->htab[ix];
+}
+
+
+__attribute__((noinline))
+static Bool find_in_StackBlocks ( /*OUT*/UWord* ix,
+ /*OUT*/Bool* isVec,
+ /*OUT*/Addr* blockEA,
+ /*OUT*/SizeT* blockSzB,
+ /*OUT*/HChar** name,
+ Addr ea, Addr sp, Addr fp,
+ UWord szB, XArray* blocks )
+{
+ Word i, n;
+ OffT delta_FP = ea - fp;
+ OffT delta_SP = ea - sp;
+ tl_assert(szB > 0 && szB <= 512);
+ n = VG_(sizeXA)( blocks );
+ for (i = 0; i < n; i++) {
+ OffT delta;
+ StackBlock* block = VG_(indexXA)( blocks, i );
+ delta = block->spRel ? delta_SP : delta_FP;
+ { Word w1 = block->base;
+ Word w2 = delta;
+ Word w3 = (Word)( ((UWord)delta) + ((UWord)szB) );
+ Word w4 = (Word)( ((UWord)block->base) + ((UWord)block->szB) );
+ if (w1 <= w2 && w3 <= w4) {
+ *ix = i;
+ *isVec = block->isVec;
+ *blockEA = block->base + (block->spRel ? sp : fp);
+ *blockSzB = block->szB;
+ *name = &block->name[0];
+ return True;
+ }
+ }
+ }
+ return False;
+}
+
+
+/* Try to classify the block into which a memory access falls, and
+ write the result in 'inv'. This writes all fields of 'inv',
+ including, importantly the ReVal (revalidation) fields. */
+__attribute__((noinline))
+static void classify_address ( /*OUT*/Invar* inv,
+ ThreadId tid,
+ Addr ea, Addr sp, Addr fp,
+ UWord szB,
+ XArray* /* of StackBlock */ thisInstrBlocks,
+ XArray* /* of StackFrame */ thisThreadFrames )
+{
+ tl_assert(szB > 0);
+ /* First, look in the stack blocks accessible in this instruction's
+ frame. */
+ {
+ UWord ix;
+ Bool isVec;
+ Addr blockEA;
+ SizeT blockSzB;
+ HChar* name;
+ Bool b = find_in_StackBlocks(
+ &ix, &isVec, &blockEA, &blockSzB, &name,
+ ea, sp, fp, szB, thisInstrBlocks
+ );
+ if (b) {
+ SizeT nameSzB = sizeof(inv->Inv.Stack.name);
+ inv->tag = isVec ? Inv_StackV : Inv_StackS;
+ inv->Inv.Stack.framesBack = 0;
+ inv->Inv.Stack.fbIndex = ix;
+ inv->Inv.Stack.start = blockEA;
+ inv->Inv.Stack.len = blockSzB;
+ VG_(memcpy)( &inv->Inv.Stack.name[0], name, nameSzB );
+ inv->Inv.Stack.name[ nameSzB-1 ] = 0;
+ stats__classify_Stack++;
+ return;
+ }
+ }
+ /* Perhaps it's a heap block? */
+ { HeapBlock* hb = find_HeapBlock_containing(ea);
+ if (hb) {
+ /* it's not possible for find_HeapBlock_containing to
+ return a block of zero size. Hence: */
+ tl_assert(hb->realSzB > 0);
+ tl_assert(hb->fakeSzB == hb->realSzB);
+ }
+ if (hb && !rangesOverlap(ea, szB, hb->addr, hb->realSzB))
+ hb = NULL;
+ if (hb) {
+ inv->tag = Inv_Heap;
+ inv->Inv.Heap.start = hb->addr;
+ inv->Inv.Heap.len = hb->realSzB;
+ stats__classify_Heap++;
+ return;
+ }
+ }
+ /* Not in a stack block. Try the global pool. */
+ { GlobalBlock* gb2 = find_GlobalBlock_containing(ea);
+ /* We know that [ea,ea+1) is in the block, but we need to
+ restrict to the case where the whole access falls within
+ it. */
+ if (gb2 && !rangesOverlap(ea, szB, gb2->addr, gb2->szB)) {
+ gb2 = NULL;
+ }
+ if (gb2) {
+ inv->tag = gb2->isVec ? Inv_GlobalV : Inv_GlobalS;
+ tl_assert(sizeof(gb2->name) == sizeof(inv->Inv.Global.name));
+ tl_assert(sizeof(gb2->soname) == sizeof(inv->Inv.Global.soname));
+ VG_(memcpy)( &inv->Inv.Global.name[0],
+ gb2->name, sizeof(gb2->name) );
+ VG_(memcpy)( &inv->Inv.Global.soname[0],
+ gb2->soname, sizeof(gb2->soname) );
+ inv->Inv.Global.start = gb2->addr;
+ inv->Inv.Global.len = gb2->szB;
+ stats__classify_Global++;
+ return;
+ }
+ }
+ /* Ok, so it's not a block in the top frame. Perhaps it's a block
+ in some calling frame? Work back down the stack to see if it's
+ an access to an array in any calling frame. */
+ {
+ UWord ix;
+ Bool isVec, b;
+ Addr blockEA;
+ SizeT blockSzB;
+ HChar* name;
+ Word n, i; /* i must remain signed */
+ StackFrame* frame;
+ n = VG_(sizeXA)( thisThreadFrames );
+ tl_assert(n > 0);
+ if (0) VG_(printf)("n = %ld\n", n);
+ i = n - 2;
+ while (1) {
+ if (i < 0) break;
+ frame = VG_(indexXA)( thisThreadFrames, i );
+ if (frame->blocks_at_call == NULL) { i--; continue; }
+ if (0) VG_(printf)("considering %ld\n", i);
+ b = find_in_StackBlocks(
+ &ix, &isVec, &blockEA, &blockSzB, &name,
+ ea, frame->sp_at_call, frame->fp_at_call, szB,
+ frame->blocks_at_call
+ );
+ if (b) {
+ SizeT nameSzB = sizeof(inv->Inv.Stack.name);
+ inv->tag = isVec ? Inv_StackV : Inv_StackS;
+ inv->Inv.Stack.framesBack = n - i - 1;;
+ inv->Inv.Stack.fbIndex = ix;
+ inv->Inv.Stack.start = blockEA;
+ inv->Inv.Stack.len = blockSzB;
+ VG_(memcpy)( &inv->Inv.Stack.name[0], name, nameSzB );
+ inv->Inv.Stack.name[ nameSzB-1 ] = 0;
+ stats__classify_Stack++;
+ return;
+ }
+ if (i == 0) break;
+ i--;
+ }
+ }
+ /* No idea - give up. We have to say it's Unknown. Note that this
+ is highly undesirable because it means we can't cache any ReVal
+ info, and so we have to do this very slow path for every access
+ made by this instruction-instance. That's why we make big
+ efforts to classify all instructions -- once classified, we can
+ do cheap ReVal checks for second and subsequent accesses. */
+ inv->tag = Inv_Unknown;
+ stats__classify_Unknown++;
+}
+
+
+/* CALLED FROM GENERATED CODE */
+static
+VG_REGPARM(3)
+void helperc__mem_access ( /* Known only at run time: */
+ Addr ea, Addr sp, Addr fp,
+ /* Known at translation time: */
+ Word sszB, Addr ip, XArray* ip_frameBlocks )
+{
+ Word n;
+ UWord szB;
+ XArray* /* of StackFrame */ frames;
+ IInstance* iinstance;
+ Invar* inv;
+ Invar new_inv;
+ ThreadId tid = VG_(get_running_tid)();
+ StackFrame* frame;
+ HChar buf[160];
+
+ stats__total_accesses++;
+
+ tl_assert(is_sane_TId(tid));
+ frames = shadowStacks[tid];
+ tl_assert(frames != NULL);
+ n = VG_(sizeXA)( frames );
+ tl_assert(n > 0);
+
+ frame = VG_(indexXA)( frames, n-1 );
+
+ /* Find the instance info for this instruction. */
+ tl_assert(ip_frameBlocks);
+ iinstance = find_or_create_IInstance( frame, ip, ip_frameBlocks );
+ tl_assert(iinstance);
+ tl_assert(iinstance->blocks == ip_frameBlocks);
+
+ szB = (sszB < 0) ? (-sszB) : sszB;
+ tl_assert(szB > 0);
+
+ inv = &iinstance->invar;
+
+ /* Deal with first uses of instruction instances. We hope this is
+ rare, because it's expensive. */
+ if (inv->tag == Inv_Unset) {
+ /* This is the first use of this instance of the instruction, so
+ we can't make any check; we merely record what we saw, so we
+ can compare it against what happens for 2nd and subsequent
+ accesses. */
+ classify_address( inv,
+ tid, ea, sp, fp, szB,
+ iinstance->blocks, frames );
+ tl_assert(inv->tag != Inv_Unset);
+ return;
+ }
+
+ /* Now, try to re-validate (ReVal). What that means is, quickly
+ establish whether or not this instruction is accessing the same
+ block as it was last time. We hope this is the common, fast
+ case. */
+ switch (inv->tag) {
+ case Inv_StackS:
+ case Inv_StackV:
+ if (inv->Inv.Stack.start <= ea
+ && ea + szB <= inv->Inv.Stack.start + inv->Inv.Stack.len) {
+ stats__reval_Stack++;
+ return; /* yay! */
+ }
+ break; /* boo! */
+ case Inv_GlobalS:
+ case Inv_GlobalV:
+ if (inv->Inv.Global.start <= ea
+ && ea + szB <= inv->Inv.Global.start + inv->Inv.Global.len) {
+ stats__reval_Global++;
+ return; /* yay! */
+ }
+ break; /* boo! */
+ case Inv_Heap:
+ if (inv->Inv.Heap.start <= ea
+ && ea + szB <= inv->Inv.Heap.start + inv->Inv.Heap.len) {
+ stats__reval_Heap++;
+ return; /* yay! */
+ }
+ break; /* boo! */
+ case Inv_Unknown:
+ break; /* boo! */
+ /* this is the undesirable case. If the instruction has
+ previously been poking around some place we can't account
+ for, we have to laboriously check all the many places
+ (blocks) we do know about, to check it hasn't transitioned
+ into any of them. */
+ default:
+ tl_assert(0);
+ }
+
+ /* We failed to quickly establish that the instruction is poking
+ around in the same block it was before. So we have to do it the
+ hard way: generate a full description (Invar) of this access,
+ and compare it to the previous Invar, to see if there are really
+ any differences. Note that we will be on this code path if the
+ program has made any invalid transitions, and so we may emit
+ error messages in the code below. */
+ classify_address( &new_inv,
+ tid, ea, sp, fp, szB,
+ iinstance->blocks, frames );
+ tl_assert(new_inv.tag != Inv_Unset);
+
+ /* Did we see something different from before? If no, then there's
+ no error. */
+ if (eq_Invar(&new_inv, inv))
+ return;
+
+ /* The new and old Invars really are different. So report an
+ error. */
+ { Bool v_old = inv->tag == Inv_StackV || inv->tag == Inv_GlobalV;
+ Bool v_new = new_inv.tag == Inv_StackV || new_inv.tag == Inv_GlobalV;
+ if ( (v_old || v_new) && new_inv.tag != inv->tag) {
+ } else {
+ goto noerror;
+ }
+ }
+
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg, "Invalid %s of size %lu",
+ sszB < 0 ? "write" : "read", szB );
+ VG_(pp_ExeContext)(
+ VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ ) );
+ // VG_(record_depth_1_ExeContext)( tid ) );
+
+ VG_(message)(Vg_UserMsg, " Address %#lx expected vs actual:", ea);
+
+ VG_(memset)(buf, 0, sizeof(buf));
+ show_Invar( buf, sizeof(buf)-1, inv );
+ VG_(message)(Vg_UserMsg, " Expected: %s", buf );
+
+ VG_(memset)(buf, 0, sizeof(buf));
+ show_Invar( buf, sizeof(buf)-1, &new_inv );
+ VG_(message)(Vg_UserMsg, " Actual: %s", buf );
+
+ noerror:
+ /* And now install the new observation as "standard", so as to
+ make future error messages make more sense. */
+ *inv = new_inv;
+}
+
+
+////////////////////////////////////////
+/* Primary push-a-new-frame routine. Called indirec...
[truncated message content] |
|
From: <sv...@va...> - 2008-08-19 11:15:03
|
Author: sewardj
Date: 2008-08-19 12:15:10 +0100 (Tue, 19 Aug 2008)
New Revision: 1864
Log:
Add a description of the FP offset/size to type VexGuestLayout.
Modified:
trunk/priv/guest-amd64/ghelpers.c
trunk/priv/guest-ppc/ghelpers.c
trunk/priv/guest-x86/ghelpers.c
trunk/pub/libvex.h
Modified: trunk/priv/guest-amd64/ghelpers.c
===================================================================
--- trunk/priv/guest-amd64/ghelpers.c 2008-08-18 21:47:52 UTC (rev 1863)
+++ trunk/priv/guest-amd64/ghelpers.c 2008-08-19 11:15:10 UTC (rev 1864)
@@ -2349,6 +2349,10 @@
.offset_SP = offsetof(VexGuestAMD64State,guest_RSP),
.sizeof_SP = 8,
+ /* Describe the frame pointer. */
+ .offset_FP = offsetof(VexGuestAMD64State,guest_RBP),
+ .sizeof_FP = 8,
+
/* Describe the instruction pointer. */
.offset_IP = offsetof(VexGuestAMD64State,guest_RIP),
.sizeof_IP = 8,
Modified: trunk/priv/guest-ppc/ghelpers.c
===================================================================
--- trunk/priv/guest-ppc/ghelpers.c 2008-08-18 21:47:52 UTC (rev 1863)
+++ trunk/priv/guest-ppc/ghelpers.c 2008-08-19 11:15:10 UTC (rev 1864)
@@ -757,6 +757,10 @@
.offset_SP = offsetof(VexGuestPPC32State,guest_GPR1),
.sizeof_SP = 4,
+ /* Describe the frame pointer. */
+ .offset_FP = offsetof(VexGuestPPC32State,guest_GPR1),
+ .sizeof_FP = 4,
+
/* Describe the instruction pointer. */
.offset_IP = offsetof(VexGuestPPC32State,guest_CIA),
.sizeof_IP = 4,
@@ -795,6 +799,10 @@
.offset_SP = offsetof(VexGuestPPC64State,guest_GPR1),
.sizeof_SP = 8,
+ /* Describe the frame pointer. */
+ .offset_FP = offsetof(VexGuestPPC64State,guest_GPR1),
+ .sizeof_FP = 8,
+
/* Describe the instruction pointer. */
.offset_IP = offsetof(VexGuestPPC64State,guest_CIA),
.sizeof_IP = 8,
Modified: trunk/priv/guest-x86/ghelpers.c
===================================================================
--- trunk/priv/guest-x86/ghelpers.c 2008-08-18 21:47:52 UTC (rev 1863)
+++ trunk/priv/guest-x86/ghelpers.c 2008-08-19 11:15:10 UTC (rev 1864)
@@ -2691,6 +2691,10 @@
.offset_SP = offsetof(VexGuestX86State,guest_ESP),
.sizeof_SP = 4,
+ /* Describe the frame pointer. */
+ .offset_FP = offsetof(VexGuestX86State,guest_EBP),
+ .sizeof_FP = 4,
+
/* Describe the instruction pointer. */
.offset_IP = offsetof(VexGuestX86State,guest_EIP),
.sizeof_IP = 4,
Modified: trunk/pub/libvex.h
===================================================================
--- trunk/pub/libvex.h 2008-08-18 21:47:52 UTC (rev 1863)
+++ trunk/pub/libvex.h 2008-08-19 11:15:10 UTC (rev 1864)
@@ -319,6 +319,9 @@
/* Whereabouts is the stack pointer? */
Int offset_SP;
Int sizeof_SP; /* 4 or 8 */
+ /* Whereabouts is the frame pointer? */
+ Int offset_FP;
+ Int sizeof_FP; /* 4 or 8 */
/* Whereabouts is the instruction pointer? */
Int offset_IP;
Int sizeof_IP; /* 4 or 8 */
|
|
From: <sv...@va...> - 2008-08-19 10:21:43
|
Author: sewardj Date: 2008-08-19 11:21:50 +0100 (Tue, 19 Aug 2008) New Revision: 8527 Log: Make a copy of trunk r8526, for the purposes of experimentation with a tool for detecting overruns on stack and global arrays. I was strongly tempted to call it SORDID (Stack Overrun Detection by Dynamic Invariant Deduction), but that's just a bit too silly. Added: branches/SGCHECK/ Copied: branches/SGCHECK (from rev 8526, trunk) Property changes on: branches/SGCHECK ___________________________________________________________________ Name: svn:ignore + acinclude.m4 aclocal.m4 autom4te-*.cache autom4te.cache bin cachegrind cachegrind.out.* compile config.guess config.h* config.log config.status config.sub configure default.supp glibc-2.X.supp depcomp include .in_place install-sh lib Makefile Makefile.in missing mkinstalldirs share stamp-h* svn-commit.tmp svn-commit.2.tmp valgrind valgrind.pc valgrind.spec valt_load_address*.lds vg_annotate vg_cachegen Name: svn:externals + VEX svn://svn.valgrind.org/vex/trunk Name: svn:mergeinfo + |
|
From: <sv...@va...> - 2008-08-19 09:52:03
|
Author: sewardj
Date: 2008-08-19 10:52:10 +0100 (Tue, 19 Aug 2008)
New Revision: 8526
Log:
Fix RPM/spec build. (Daniel J Blueman)
Modified:
trunk/valgrind.spec.in
Modified: trunk/valgrind.spec.in
===================================================================
--- trunk/valgrind.spec.in 2008-08-19 08:57:49 UTC (rev 8525)
+++ trunk/valgrind.spec.in 2008-08-19 09:52:10 UTC (rev 8526)
@@ -40,7 +40,7 @@
%files
%defattr(-,root,root)
%doc ACKNOWLEDGEMENTS AUTHORS COPYING FAQ.txt INSTALL NEWS README*
-%doc docs.installed/*.html docs.installed/*.gif
+%doc docs.installed/html/*.html docs.installed/html/images/*.png
%{_bindir}/*
%{_includedir}/valgrind
%{_libdir}/valgrind
|
|
From: <sv...@va...> - 2008-08-19 08:57:41
|
Author: sewardj
Date: 2008-08-19 09:57:49 +0100 (Tue, 19 Aug 2008)
New Revision: 8525
Log:
Make VG_(addToXA) and VG_(addBytesToXA) 64-bit clean.
Modified:
trunk/coregrind/m_debuginfo/storage.c
trunk/coregrind/m_xarray.c
trunk/include/pub_tool_xarray.h
Modified: trunk/coregrind/m_debuginfo/storage.c
===================================================================
--- trunk/coregrind/m_debuginfo/storage.c 2008-08-19 08:38:52 UTC (rev 8524)
+++ trunk/coregrind/m_debuginfo/storage.c 2008-08-19 08:57:49 UTC (rev 8525)
@@ -420,7 +420,7 @@
CfiExpr e;
VG_(memset)( &e, 0, sizeof(e) );
e.tag = Cex_Undef;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
Int ML_(CfiExpr_Deref)( XArray* dst, Int ixAddr )
{
@@ -428,7 +428,7 @@
VG_(memset)( &e, 0, sizeof(e) );
e.tag = Cex_Deref;
e.Cex.Deref.ixAddr = ixAddr;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
Int ML_(CfiExpr_Const)( XArray* dst, UWord con )
{
@@ -436,7 +436,7 @@
VG_(memset)( &e, 0, sizeof(e) );
e.tag = Cex_Const;
e.Cex.Const.con = con;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
Int ML_(CfiExpr_Binop)( XArray* dst, CfiOp op, Int ixL, Int ixR )
{
@@ -446,7 +446,7 @@
e.Cex.Binop.op = op;
e.Cex.Binop.ixL = ixL;
e.Cex.Binop.ixR = ixR;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
Int ML_(CfiExpr_CfiReg)( XArray* dst, CfiReg reg )
{
@@ -454,7 +454,7 @@
VG_(memset)( &e, 0, sizeof(e) );
e.tag = Cex_CfiReg;
e.Cex.CfiReg.reg = reg;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
Int ML_(CfiExpr_DwReg)( XArray* dst, Int reg )
{
@@ -462,7 +462,7 @@
VG_(memset)( &e, 0, sizeof(e) );
e.tag = Cex_DwReg;
e.Cex.DwReg.reg = reg;
- return VG_(addToXA)( dst, &e );
+ return (Int)VG_(addToXA)( dst, &e );
}
static void ppCfiOp ( CfiOp op )
Modified: trunk/coregrind/m_xarray.c
===================================================================
--- trunk/coregrind/m_xarray.c 2008-08-19 08:38:52 UTC (rev 8524)
+++ trunk/coregrind/m_xarray.c 2008-08-19 08:57:49 UTC (rev 8525)
@@ -165,7 +165,7 @@
}
}
-Int VG_(addToXA) ( XArray* xao, void* elem )
+Word VG_(addToXA) ( XArray* xao, void* elem )
{
struct _XArray* xa = (struct _XArray*)xao;
vg_assert(xa);
@@ -182,9 +182,9 @@
return xa->usedsizeE-1;
}
-Int VG_(addBytesToXA) ( XArray* xao, void* bytesV, Int nbytes )
+Word VG_(addBytesToXA) ( XArray* xao, void* bytesV, Word nbytes )
{
- Int r, i;
+ Word r, i;
struct _XArray* xa = (struct _XArray*)xao;
vg_assert(xa);
vg_assert(xa->elemSzB == 1);
Modified: trunk/include/pub_tool_xarray.h
===================================================================
--- trunk/include/pub_tool_xarray.h 2008-08-19 08:38:52 UTC (rev 8524)
+++ trunk/include/pub_tool_xarray.h 2008-08-19 08:57:49 UTC (rev 8525)
@@ -64,12 +64,12 @@
/* Add an element to an XArray. Element is copied into the XArray.
Index at which it was added is returned. Note this will be
invalidated if the array is later sortXA'd. */
-extern Int VG_(addToXA) ( XArray*, void* elem );
+extern Word VG_(addToXA) ( XArray*, void* elem );
/* Add a sequence of bytes to an XArray of bytes. Asserts if nbytes
is negative or the array's element size is not 1. Returns the
index at which the first byte was added. */
-extern Int VG_(addBytesToXA) ( XArray* xao, void* bytesV, Int nbytes );
+extern Word VG_(addBytesToXA) ( XArray* xao, void* bytesV, Word nbytes );
/* Sort an XArray using its comparison function, if set; else bomb.
Probably not a stable sort w.r.t. equal elements module cmpFn. */
|
|
From: <sv...@va...> - 2008-08-19 08:38:45
|
Author: sewardj Date: 2008-08-19 09:38:52 +0100 (Tue, 19 Aug 2008) New Revision: 8524 Log: Move the WordFM (AVL trees of UWord-pairs) implementation from helgrind/ into the core. It's just too darn useful to not be in the core. There is some overlap in functionality between OSet and WordFM, but OSet is more space efficient in some circumstances, whereas WordFM is easier to use and a bit more flexible in some cases. Also in this new module (m_wordfm) is a type WordBag, build on top of WordFM. This provides Multiset of UWords functionality. Added: trunk/coregrind/m_wordfm.c trunk/coregrind/pub_core_wordfm.h trunk/include/pub_tool_wordfm.h Removed: trunk/helgrind/hg_wordfm.c trunk/helgrind/hg_wordfm.h Modified: trunk/coregrind/Makefile.am trunk/helgrind/Makefile.am trunk/helgrind/hg_main.c trunk/helgrind/hg_wordset.c trunk/include/Makefile.am [... diff too large to include ...] |
|
From: <sv...@va...> - 2008-08-19 08:31:55
|
Author: sewardj
Date: 2008-08-19 09:32:03 +0100 (Tue, 19 Aug 2008)
New Revision: 8523
Log:
Tidy up VG_(stat) usage in VG_(check_executable). Followup to r8522.
Modified:
trunk/coregrind/m_libcfile.c
Modified: trunk/coregrind/m_libcfile.c
===================================================================
--- trunk/coregrind/m_libcfile.c 2008-08-19 07:03:04 UTC (rev 8522)
+++ trunk/coregrind/m_libcfile.c 2008-08-19 08:32:03 UTC (rev 8523)
@@ -401,17 +401,8 @@
Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
HChar* f, Bool allow_setuid)
{
- /* This is something of a kludge. Really we should fix VG_(stat) to
- do this itself, but not clear how to do it as it depends on
- having a 'struct vki_stat64' which is different from 'struct
- vki_stat'. */
-# if defined(VGO_linux) && defined(__NR_stat64)
- struct vki_stat64 st;
- SysRes res = VG_(do_syscall2)(__NR_stat64, (UWord)f, (UWord)&st);
-# else
- struct vki_stat st;
+ struct vg_stat st;
SysRes res = VG_(stat)(f, &st);
-# endif
if (is_setuid)
*is_setuid = False;
|
|
From: <sv...@va...> - 2008-08-19 07:02:56
|
Author: sewardj
Date: 2008-08-19 08:03:04 +0100 (Tue, 19 Aug 2008)
New Revision: 8522
Log:
Presently, Valgrind (non-client) code that wants to use the stat
family of syscalls is impossible to write in a way that's portable and
correct. On some targets (eg x86-linux) you need to do sys_stat64 and
receive the results in a 'struct vki_stat64'. But on other targets
(eg amd64-linux) neither sys_stat64 nor 'struct vki_stat64' exist.
This commit adds a new type, 'struct vg_stat', which contains 64 bit
fields in all the right places, and makes VG_(stat) and VG_(fstat) use
it. This means callers to the two functions no longer need to worry
about the is-it-64-bit-clean-or-not question, since these routines
reformat the received data into a'struct vg_stat'. Kind of like what
glibc must have been doing for decades.
This (indirectly) fixes a bug on x86-linux, in which m_debuginfo would
sometimes fail to read debug info, due to VG_(di_notify_mmap) using
VG_(stat) (hence sys_stat) on the file, which failed, and when in fact
it should have used sys_stat64. Bug reported and tracked down by
Marc-Oliver Straub.
Modified:
trunk/coregrind/m_commandline.c
trunk/coregrind/m_debuginfo/debuginfo.c
trunk/coregrind/m_debuginfo/readelf.c
trunk/coregrind/m_libcfile.c
trunk/coregrind/m_ume.c
trunk/coregrind/pub_core_libcfile.h
trunk/include/pub_tool_libcfile.h
Modified: trunk/coregrind/m_commandline.c
===================================================================
--- trunk/coregrind/m_commandline.c 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/m_commandline.c 2008-08-19 07:03:04 UTC (rev 8522)
@@ -57,7 +57,7 @@
{
Int n;
SysRes fd;
- Int size;
+ Long size;
HChar* f_clo = NULL;
HChar filename[VKI_PATH_MAX];
Modified: trunk/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- trunk/coregrind/m_debuginfo/debuginfo.c 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/m_debuginfo/debuginfo.c 2008-08-19 07:03:04 UTC (rev 8522)
@@ -491,8 +491,8 @@
Int nread;
HChar buf1k[1024];
Bool debug = False;
- SysRes statres;
- struct vki_stat statbuf;
+ SysRes statres;
+ struct vg_stat statbuf;
/* In short, figure out if this mapping is of interest to us, and
if so, try to guess what ld.so is doing and when/if we should
@@ -522,17 +522,33 @@
if (debug)
VG_(printf)("di_notify_mmap-2: %s\n", filename);
- /* Only try to read debug information from regular files. */
+ /* Only try to read debug information from regular files. */
statres = VG_(stat)(filename, &statbuf);
- /* If the assert below ever fails, replace the VG_(stat)() call above */
- /* by a VG_(lstat)() call. */
+
+ /* stat dereferences symlinks, so we don't expect it to succeed and
+ yet produce something that is a symlink. */
vg_assert(statres.isError || ! VKI_S_ISLNK(statbuf.st_mode));
- if (statres.isError || ! VKI_S_ISREG(statbuf.st_mode))
- {
+
+ /* Don't let the stat call fail silently. Filter out some known
+ sources of noise before complaining, though. */
+ if (statres.isError) {
+ DebugInfo fake_di;
+ Bool quiet = VG_(strstr)(filename, "/var/run/nscd/") != NULL;
+ if (!quiet) {
+ VG_(memset)(&fake_di, 0, sizeof(fake_di));
+ fake_di.filename = filename;
+ ML_(symerr)(&fake_di, True, "failed to stat64/stat this file");
+ }
return;
}
+ /* Finally, the point of all this stattery: if it's not a regular file,
+ don't try to read debug info from it. */
+ if (! VKI_S_ISREG(statbuf.st_mode))
+ return;
+ /* no uses of statbuf below here. */
+
/* Peer at the first few bytes of the file, to see if it is an ELF */
/* object file. Ignore the file if we do not have read permission. */
VG_(memset)(buf1k, 0, sizeof(buf1k));
Modified: trunk/coregrind/m_debuginfo/readelf.c
===================================================================
--- trunk/coregrind/m_debuginfo/readelf.c 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/m_debuginfo/readelf.c 2008-08-19 07:03:04 UTC (rev 8522)
@@ -859,7 +859,7 @@
Addr open_debug_file( Char* name, UInt crc, /*OUT*/UWord* size )
{
SysRes fd, sres;
- struct vki_stat stat_buf;
+ struct vg_stat stat_buf;
UInt calccrc;
fd = VG_(open)(name, VKI_O_RDONLY, 0);
@@ -1083,11 +1083,13 @@
return False;
}
- n_oimage = VG_(fsize)(fd.res);
- if (n_oimage <= 0) {
- ML_(symerr)(di, True, "Can't stat .so/.exe (to determine its size)?!");
- VG_(close)(fd.res);
- return False;
+ { Long n_oimageLL = VG_(fsize)(fd.res);
+ if (n_oimageLL <= 0) {
+ ML_(symerr)(di, True, "Can't stat .so/.exe (to determine its size)?!");
+ VG_(close)(fd.res);
+ return False;
+ }
+ n_oimage = (UWord)(ULong)n_oimageLL;
}
sres = VG_(am_mmap_file_float_valgrind)
Modified: trunk/coregrind/m_libcfile.c
===================================================================
--- trunk/coregrind/m_libcfile.c 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/m_libcfile.c 2008-08-19 07:03:04 UTC (rev 8522)
@@ -47,8 +47,7 @@
static inline Bool fd_exists(Int fd)
{
- struct vki_stat st;
-
+ struct vg_stat st;
return VG_(fstat)(fd, &st) == 0;
}
@@ -139,28 +138,89 @@
change VG_(pread) and all other usage points. */
}
-SysRes VG_(stat) ( Char* file_name, struct vki_stat* buf )
+
+/* stat/fstat support. It's uggerly. We have impedance-match into a
+ 'struct vg_stat' in order to have a single structure that callers
+ can use consistently on all platforms. */
+
+#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
+ do { \
+ (_p_vgstat)->st_dev = (ULong)( (_p_vkistat)->st_dev ); \
+ (_p_vgstat)->st_ino = (ULong)( (_p_vkistat)->st_ino ); \
+ (_p_vgstat)->st_nlink = (ULong)( (_p_vkistat)->st_nlink ); \
+ (_p_vgstat)->st_mode = (UInt)( (_p_vkistat)->st_mode ); \
+ (_p_vgstat)->st_uid = (UInt)( (_p_vkistat)->st_uid ); \
+ (_p_vgstat)->st_gid = (UInt)( (_p_vkistat)->st_gid ); \
+ (_p_vgstat)->st_rdev = (ULong)( (_p_vkistat)->st_rdev ); \
+ (_p_vgstat)->st_size = (Long)( (_p_vkistat)->st_size ); \
+ (_p_vgstat)->st_blksize = (ULong)( (_p_vkistat)->st_blksize ); \
+ (_p_vgstat)->st_blocks = (ULong)( (_p_vkistat)->st_blocks ); \
+ (_p_vgstat)->st_atime = (ULong)( (_p_vkistat)->st_atime ); \
+ (_p_vgstat)->st_atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
+ (_p_vgstat)->st_mtime = (ULong)( (_p_vkistat)->st_mtime ); \
+ (_p_vgstat)->st_mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
+ (_p_vgstat)->st_ctime = (ULong)( (_p_vkistat)->st_ctime ); \
+ (_p_vgstat)->st_ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
+ } while (0)
+
+SysRes VG_(stat) ( Char* file_name, struct vg_stat* vgbuf )
{
+ SysRes res;
+ VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
# if defined(VGO_linux)
- SysRes res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)buf);
- return res;
+# if defined(__NR_stat64)
+ { struct vki_stat64 buf64;
+ res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
+ if (!(res.isError && res.err == VKI_ENOSYS)) {
+ /* Success, or any failure except ENOSYS */
+ if (!res.isError)
+ TRANSLATE_TO_vg_stat(vgbuf, &buf64);
+ return res;
+ }
+ }
+# endif /* if defined(__NR_stat64) */
+ { struct vki_stat buf;
+ res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
+ if (!res.isError)
+ TRANSLATE_TO_vg_stat(vgbuf, &buf);
+ return res;
+ }
# elif defined(VGO_aix5)
- SysRes res = VG_(do_syscall4)(__NR_AIX5_statx,
- (UWord)file_name,
- (UWord)buf,
- sizeof(struct vki_stat),
- VKI_STX_NORMAL);
+ res = VG_(do_syscall4)(__NR_AIX5_statx,
+ (UWord)file_name,
+ (UWord)buf,
+ sizeof(struct vki_stat),
+ VKI_STX_NORMAL);
+ if (!res.isError)
+ TRANSLATE_TO_vg_stat(vgbuf, &buf);
return res;
# else
# error Unknown OS
# endif
}
-Int VG_(fstat) ( Int fd, struct vki_stat* buf )
+Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
{
+ SysRes res;
+ VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
# if defined(VGO_linux)
- SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)buf);
- return res.isError ? (-1) : 0;
+# if defined(__NR_fstat64)
+ { struct vki_stat64 buf64;
+ res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
+ if (!(res.isError && res.err == VKI_ENOSYS)) {
+ /* Success, or any failure except ENOSYS */
+ if (!res.isError)
+ TRANSLATE_TO_vg_stat(vgbuf, &buf64);
+ return res.isError ? (-1) : 0;
+ }
+ }
+# endif /* if defined(__NR_fstat64) */
+ { struct vki_stat buf;
+ res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
+ if (!res.isError)
+ TRANSLATE_TO_vg_stat(vgbuf, &buf);
+ return res.isError ? (-1) : 0;
+ }
# elif defined(VGO_aix5)
I_die_here;
# else
@@ -168,26 +228,19 @@
# endif
}
-Int VG_(fsize) ( Int fd )
+#undef TRANSLATE_TO_vg_stat
+
+
+Long VG_(fsize) ( Int fd )
{
-# if defined(VGO_linux) && defined(__NR_fstat64)
- struct vki_stat64 buf;
- SysRes res = VG_(do_syscall2)(__NR_fstat64, fd, (UWord)&buf);
- return res.isError ? (-1) : buf.st_size;
-# elif defined(VGO_linux) && !defined(__NR_fstat64)
- struct vki_stat buf;
- SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
- return res.isError ? (-1) : buf.st_size;
-# elif defined(VGO_aix5)
- I_die_here;
-# else
-# error Unknown OS
-# endif
+ struct vg_stat buf;
+ Int res = VG_(fstat)( fd, &buf );
+ return (res == -1) ? (-1LL) : buf.st_size;
}
Bool VG_(is_dir) ( HChar* f )
{
- struct vki_stat buf;
+ struct vg_stat buf;
SysRes res = VG_(stat)(f, &buf);
return res.isError ? False
: VKI_S_ISDIR(buf.st_mode) ? True : False;
Modified: trunk/coregrind/m_ume.c
===================================================================
--- trunk/coregrind/m_ume.c 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/m_ume.c 2008-08-19 07:03:04 UTC (rev 8522)
@@ -669,7 +669,7 @@
return VG_(mk_SysRes_Error)(ret);
}
- fsz = VG_(fsize)(fd);
+ fsz = (SizeT)VG_(fsize)(fd);
if (fsz < bufsz)
bufsz = fsz;
@@ -773,7 +773,7 @@
{
Char* default_interp_name = "/bin/sh";
SysRes res;
- struct vki_stat st;
+ struct vg_stat st;
if (VKI_ENOEXEC == ret) {
// It was an executable file, but in an unacceptable format. Probably
Modified: trunk/coregrind/pub_core_libcfile.h
===================================================================
--- trunk/coregrind/pub_core_libcfile.h 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/coregrind/pub_core_libcfile.h 2008-08-19 07:03:04 UTC (rev 8522)
@@ -46,8 +46,8 @@
/* Convert an fd into a filename */
extern Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf );
-/* Return the size of a file */
-extern Int VG_(fsize) ( Int fd );
+/* Return the size of a file, or -1 in case of error */
+extern Long VG_(fsize) ( Int fd );
/* Is the file a directory? */
extern Bool VG_(is_dir) ( HChar* f );
Modified: trunk/include/pub_tool_libcfile.h
===================================================================
--- trunk/include/pub_tool_libcfile.h 2008-08-18 21:47:11 UTC (rev 8521)
+++ trunk/include/pub_tool_libcfile.h 2008-08-19 07:03:04 UTC (rev 8522)
@@ -37,6 +37,32 @@
/* To use this file you must first include pub_tool_vki.h. */
+/* Note that VG_(stat) and VG_(fstat) write to a 'struct vg_stat*' and
+ not a 'struct vki_stat*' or a 'struct vki_stat64*'. 'struct
+ vg_stat*' is not the same as either of the vki_ versions. No
+ specific vki_stat{,64} kernel structure will work and is
+ consistently available on different architectures on Linux, so we
+ have to use this 'struct vg_stat' impedance-matching type
+ instead. */
+struct vg_stat {
+ ULong st_dev;
+ ULong st_ino;
+ ULong st_nlink;
+ UInt st_mode;
+ UInt st_uid;
+ UInt st_gid;
+ ULong st_rdev;
+ Long st_size;
+ ULong st_blksize;
+ ULong st_blocks;
+ ULong st_atime;
+ ULong st_atime_nsec;
+ ULong st_mtime;
+ ULong st_mtime_nsec;
+ ULong st_ctime;
+ ULong st_ctime_nsec;
+};
+
extern SysRes VG_(open) ( const Char* pathname, Int flags, Int mode );
extern void VG_(close) ( Int fd );
extern Int VG_(read) ( Int fd, void* buf, Int count);
@@ -44,8 +70,8 @@
extern Int VG_(pipe) ( Int fd[2] );
extern OffT VG_(lseek) ( Int fd, OffT offset, Int whence );
-extern SysRes VG_(stat) ( Char* file_name, struct vki_stat* buf );
-extern Int VG_(fstat) ( Int fd, struct vki_stat* buf );
+extern SysRes VG_(stat) ( Char* file_name, struct vg_stat* buf );
+extern Int VG_(fstat) ( Int fd, struct vg_stat* buf );
extern SysRes VG_(dup) ( Int oldfd );
extern Int VG_(rename) ( Char* old_name, Char* new_name );
extern Int VG_(unlink) ( Char* file_name );
|
|
From: Tom H. <th...@cy...> - 2008-08-19 03:04:45
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2008-08-19 03:15:02 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 == 345 tests, 60 stderr failures, 1 stdout failure, 29 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/leak-0 (stderr) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-regroot (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/long_namespace_xml (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/origin1-yes (stderr) memcheck/tests/origin4-many (stderr) memcheck/tests/origin5-bz2 (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_changes (stderr) memcheck/tests/varinfo1 (stderr) memcheck/tests/varinfo2 (stderr) memcheck/tests/varinfo3 (stderr) memcheck/tests/varinfo4 (stderr) memcheck/tests/varinfo5 (stderr) memcheck/tests/varinfo6 (stderr) memcheck/tests/x86/bug152022 (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) memcheck/tests/x86/xor-undef-x86 (stderr) memcheck/tests/xml1 (stderr) massif/tests/alloc-fns-A (post) massif/tests/alloc-fns-B (post) massif/tests/basic (post) massif/tests/basic2 (post) massif/tests/big-alloc (post) massif/tests/culling1 (stderr) massif/tests/culling2 (stderr) massif/tests/custom_alloc (post) massif/tests/deep-A (post) massif/tests/deep-B (stderr) massif/tests/deep-B (post) massif/tests/deep-C (stderr) massif/tests/deep-C (post) massif/tests/deep-D (post) massif/tests/ignoring (post) massif/tests/insig (post) massif/tests/long-names (post) massif/tests/long-time (post) massif/tests/new-cpp (post) massif/tests/null (post) massif/tests/one (post) massif/tests/overloaded-new (post) massif/tests/peak (post) massif/tests/peak2 (stderr) massif/tests/peak2 (post) massif/tests/realloc (stderr) massif/tests/realloc (post) massif/tests/thresholds_0_0 (post) massif/tests/thresholds_0_10 (post) massif/tests/thresholds_10_0 (post) massif/tests/thresholds_10_10 (post) massif/tests/thresholds_5_0 (post) massif/tests/thresholds_5_10 (post) massif/tests/zero1 (post) massif/tests/zero2 (post) none/tests/blockfault (stderr) none/tests/mremap2 (stdout) none/tests/shell (stderr) none/tests/shell_valid1 (stderr) none/tests/shell_valid2 (stderr) none/tests/shell_valid3 (stderr) helgrind/tests/hg01_all_ok (stderr) helgrind/tests/hg02_deadlock (stderr) helgrind/tests/hg03_inherit (stderr) helgrind/tests/hg04_race (stderr) helgrind/tests/hg05_race2 (stderr) helgrind/tests/hg06_readshared (stderr) helgrind/tests/tc01_simple_race (stderr) helgrind/tests/tc02_simple_tls (stderr) helgrind/tests/tc03_re_excl (stderr) helgrind/tests/tc05_simple_race (stderr) helgrind/tests/tc06_two_races (stderr) helgrind/tests/tc07_hbl1 (stderr) helgrind/tests/tc08_hbl2 (stderr) helgrind/tests/tc09_bad_unlock (stderr) helgrind/tests/tc11_XCHG (stderr) helgrind/tests/tc12_rwl_trivial (stderr) helgrind/tests/tc14_laog_dinphils (stderr) helgrind/tests/tc16_byterace (stderr) helgrind/tests/tc17_sembar (stderr) helgrind/tests/tc18_semabuse (stderr) helgrind/tests/tc19_shadowmem (stderr) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc21_pthonce (stderr) helgrind/tests/tc22_exit_w_lock (stderr) helgrind/tests/tc23_bogus_condwait (stderr) helgrind/tests/tc24_nonzero_sem (stderr) |
|
From: Tom H. <th...@cy...> - 2008-08-19 02:56:12
|
Nightly build on aston ( x86_64, Fedora Core 5 ) started at 2008-08-19 03:20:04 BST Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 443 tests, 8 stderr failures, 1 stdout failure, 0 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) none/tests/blockfault (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc21_pthonce (stderr) helgrind/tests/tc22_exit_w_lock (stderr) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 443 tests, 7 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) none/tests/blockfault (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc08_hbl2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Tue Aug 19 03:38:14 2008 --- new.short Tue Aug 19 03:56:20 2008 *************** *** 8,10 **** ! == 443 tests, 7 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/file_locking (stderr) --- 8,10 ---- ! == 443 tests, 8 stderr failures, 1 stdout failure, 0 post failures == memcheck/tests/file_locking (stderr) *************** *** 15,18 **** none/tests/mremap2 (stdout) - helgrind/tests/tc08_hbl2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) --- 15,18 ---- none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) + helgrind/tests/tc21_pthonce (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-08-19 02:42:38
|
Nightly build on lloyd ( x86_64, Fedora 7 ) started at 2008-08-19 03:05:05 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 == 437 tests, 6 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-08-19 02:41:45
|
Nightly build on trojan ( x86_64, Fedora Core 6 ) started at 2008-08-19 03:25:05 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 == 441 tests, 8 stderr failures, 5 stdout failures, 0 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/bug133694 (stdout) memcheck/tests/x86/bug133694 (stderr) memcheck/tests/x86/scalar (stderr) none/tests/cmdline1 (stdout) none/tests/cmdline2 (stdout) none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc21_pthonce (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-08-19 02:23:38
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2008-08-19 03:00:05 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 == 443 tests, 31 stderr failures, 3 stdout failures, 0 post failures == memcheck/tests/file_locking (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/origin5-bz2 (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/varinfo6 (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/amd64/insn_ssse3 (stdout) none/tests/amd64/insn_ssse3 (stderr) none/tests/amd64/ssse3_misaligned (stderr) none/tests/blockfault (stderr) none/tests/fdleak_fcntl (stderr) none/tests/mremap2 (stdout) none/tests/x86/insn_ssse3 (stdout) none/tests/x86/insn_ssse3 (stderr) none/tests/x86/ssse3_misaligned (stderr) helgrind/tests/hg01_all_ok (stderr) helgrind/tests/hg02_deadlock (stderr) helgrind/tests/hg03_inherit (stderr) helgrind/tests/hg04_race (stderr) helgrind/tests/hg05_race2 (stderr) helgrind/tests/tc01_simple_race (stderr) helgrind/tests/tc05_simple_race (stderr) helgrind/tests/tc06_two_races (stderr) helgrind/tests/tc09_bad_unlock (stderr) helgrind/tests/tc14_laog_dinphils (stderr) helgrind/tests/tc16_byterace (stderr) helgrind/tests/tc17_sembar (stderr) helgrind/tests/tc19_shadowmem (stderr) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc21_pthonce (stderr) helgrind/tests/tc22_exit_w_lock (stderr) helgrind/tests/tc23_bogus_condwait (stderr) |