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
(6) |
2
(7) |
|
3
(12) |
4
(9) |
5
(12) |
6
(9) |
7
(18) |
8
(10) |
9
(17) |
|
10
(15) |
11
(22) |
12
(16) |
13
(18) |
14
(9) |
15
(14) |
16
(18) |
|
17
(24) |
18
(11) |
19
(15) |
20
(29) |
21
(19) |
22
(20) |
23
(9) |
|
24
(25) |
25
(25) |
26
(38) |
27
(22) |
28
(16) |
29
(17) |
|
|
From: Philippe W. <phi...@sk...> - 2008-02-17 22:08:49
|
Hello,
Since my original post, some progress has been done:
* the gdbserver code (about 6500 lines of wc *.c) has been changed to use VG_() instead of libc
This was relatively mechanical (e.g. I did some simple emacs lisp to replace various libc calls
by VG_ equivalent. If someone is interested, I can post it).
* a minimal "low target" for valgrind/X86 allows to read/write memory and registers + continue execution
All that resulted in a "basic" working remote debugging of the valgrind client:
After the first error, valgrind waits for gdb to attach via the remote protocol
gdb can then examine/modify the memory. The continue command continues the execution
till the next error. valgrind then gives back the control to the gdb remote stub.
(in other words, except that the memory of the client can be modified, it is basically provides
the same features as the current --db-attach)
Many things are not done yet (e.g. threads not properly supported, no breakpoint, no step, no watchpoint)
In parallel, I have received a private mail from someone telling me that his company has developped
a gdb remote stub for valgrind (as part of another bigger work) and that this should be contributed
soon to valgrind. This stub is more advanced than what I have done (e.g. supports threads, more architectures),
and so I think I better continue to work based on this stub (when it is checked in).
In summary, we have another new stub born :).
This gdb stub is however also not (yet) supporting breakpoints/watchpoints/step, so that looks the
next thing to look at: it would be nice if gdb debugging a valgrind client would support:
breakpoint/continue
step/continue
watchpoints (read, write, access)/continue
How to implement breakpoint is not clear to me, I put below some ideas.
Any feedback about this (or even better, give the really good idea about how to do that) will be
very much appreciated
Approach "vex TRAP"
--------------------------------
Have a "vex TRAP " instruction doing no effect, except to stop the execution
and give back the control to the gdb remote stub.
With this, to put a break, the following then needs to be done:
* if the block in which the break has to be put is translated, then discard the translation
* add the desired break address in a list of breaks
* in the JITter translater, when translating a block, insert the special "vex TRAP" instruction
if the list of breaks contains an address inside the block being translated
Probably this would be reasonably efficient for normal breaks.
However, it is not clear how this would work for "single step": I assume that it is not possible
to insert a TRAP instruction in a block being executed.
Approach "memory protection"
--------------------------------------------
Another approach might be to use some internal valgrind memory management mechanism:
if in valgrind, it is possible to change the "protection" of a specific memory location,
then it would be enough to make a memory location "not executable" (for a break),
"not writeable" and/or "not readable" for a watchpoint.
I do not know if valgrind has such a fine-grain memory protection.
In this schema, a single step is also not clear to me.
Any hint/guidance will be welcome
Philippe
|
|
From: Nicholas N. <nj...@cs...> - 2008-02-17 20:57:07
|
On Sun, 17 Feb 2008 sv...@va... wrote: > +to and reading from the shared memory. Since the invention of the > +multithreading concept, there is an ongoing debate about which way to > +model concurrent activities is better -- shared memory programming or > +message passing [Ousterhout 1996]. Isn't what you've called here "multithreading" more typically called "shared memory multithreading" or something like that? Nice write-up, BTW. Nick |
|
From: <sv...@va...> - 2008-02-17 20:54:12
|
Author: sewardj
Date: 2008-02-17 20:54:12 +0000 (Sun, 17 Feb 2008)
New Revision: 7421
Log:
Misc tidying, including better comments, and better checking of info
passed to ML_(addVar).
Modified:
branches/DATASYMS/coregrind/m_debuginfo/d3basics.c
branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
branches/DATASYMS/coregrind/m_debuginfo/readelf.c
branches/DATASYMS/coregrind/m_debuginfo/storage.c
branches/DATASYMS/coregrind/m_debuginfo/tytypes.c
Modified: branches/DATASYMS/coregrind/m_debuginfo/d3basics.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/d3basics.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/d3basics.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -472,6 +472,14 @@
sw1 = (Word)read_leb128S( &expr );
PUSH( fbval.res + sw1 );
break;
+ /* DW_OP_breg* denotes 'contents of specified register, plus
+ constant offset'. So provided we know what the register's
+ value is, we can evaluate this. Contrast DW_OP_reg*,
+ which indicates that denoted location is in a register
+ itself. For DW_OP_reg* we must always fail, since this
+ function is intended to compute a memory address of some
+ kind. See D3 Spec sec 2.6.1 ("Register Name Operations")
+ for details. */
case DW_OP_breg0 ... DW_OP_breg31:
if (!regs)
FAIL("evaluate_Dwarf3_Expr: DW_OP_breg* but no reg info");
@@ -493,6 +501,7 @@
"Warning: DWARF3 CFI reader: unhandled DW_OP_ "
"opcode 0x%x", (Int)opcode);
FAIL("evaluate_Dwarf3_Expr: unhandled DW_OP_");
+ /*NOTREACHED*/
}
}
Modified: branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -1444,7 +1444,7 @@
inapplicable DebugInfos quickly. */
if (si->cfsi_used == 0)
continue;
- if (*ipP < si->cfsi_minaddr || *ipP > si->cfsi_maxaddr)
+ if (*ipP < si->cfsi_minavma || *ipP > si->cfsi_maxavma)
continue;
i = ML_(search_one_cfitab)( si, *ipP );
Modified: branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h 2008-02-17 20:54:12 UTC (rev 7421)
@@ -350,8 +350,8 @@
DiCfSI* cfsi;
UInt cfsi_used;
UInt cfsi_size;
- Addr cfsi_minaddr;
- Addr cfsi_maxaddr;
+ Addr cfsi_minavma;
+ Addr cfsi_maxavma;
XArray* cfsi_exprs; /* XArray of CfiExpr */
/* Expandable arrays of characters -- the string table. Pointers
Modified: branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -34,19 +34,55 @@
without prior written permission.
*/
-/* Current hacks:
- DW_TAG_{const,volatile}_type no DW_AT_type is allowed; it is
- assumed to mean "const void" or "volatile void" respectively.
- GDB appears to interpret them like this, anyway.
+/* REFERENCE (without which this code will not make much sense):
+ DWARF Debugging Information Format, Version 3,
+ dated 20 December 2005 (the "D3 spec").
+
+ Available at http://www.dwarfstd.org/Dwarf3.pdf. There's also a
+ .doc (MS Word) version, but for some reason the section numbers
+ between the Word and PDF versions differ by 1 in the first digit.
+ All section references in this code are to the PDF version.
+
+ CURRENT HACKS:
+
+ DW_TAG_{const,volatile}_type no DW_AT_type is allowed; it is
+ assumed to mean "const void" or "volatile void" respectively.
+ GDB appears to interpret them like this, anyway.
+
+ In many cases it is important to know the svma of a CU (the "base
+ address of the CU", as the D3 spec calls it). There are some
+ situations in which the spec implies this value is unknown, but the
+ Dwarf3 produced by gcc-4.1 seems to assume is not unknown but
+ merely zero when not explicitly stated. So we too have to make
+ that assumption.
+
+ TODO, 2008 Feb 17:
+
get rid of cu_svma_known and document the assumed-zero svma hack.
- (text)-bias the code ranges handed to ML_(addVar); add check that
- they actually fall into the text segment
+ ML_(sizeOfType): differentiate between zero sized types and types
+ for which the size is unknown. Is this important? I don't know.
- parse all the types first, then resolve, then parse all the vars,
- so that when we come to add vars, we know what their types are.
- This is important, else we cannot know their sizes.
+ DW_AT_array_types: deal with explicit sizes (currently we compute
+ the size from the bounds and the element size, although that's
+ fragile, if the bounds incompletely specified, or completely
+ absent)
+
+ Document reason for difference (by 1) of stack preening depth in
+ parse_var_DIE vs parse_type_DIE.
+
+ Don't hand to ML_(addVars), vars whose locations are entirely in
+ registers (DW_OP_reg*). This is merely a space-saving
+ optimisation, as ML_(evaluate_Dwarf3_Expr) should handle these
+ expressions correctly, by failing to evaluate them and hence
+ effectively ignoring the variable with which they are associated.
+
+ Deal with DW_AT_array_types which have element size != stride
+
+ In some cases, the info for a variable is split between two
+ different DIEs (generally a declarer and a definer). We punt on
+ these. Could do better here.
*/
#include "pub_core_basics.h"
@@ -118,11 +154,11 @@
return c->region_next >= c->region_szB;
}
-static Word get_position_of_Cursor ( Cursor* c ) {
+static inline UWord get_position_of_Cursor ( Cursor* c ) {
vg_assert(is_sane_Cursor(c));
return c->region_next;
}
-static void set_position_of_Cursor ( Cursor* c, Word pos ) {
+static inline void set_position_of_Cursor ( Cursor* c, UWord pos ) {
c->region_next = pos;
vg_assert(is_sane_Cursor(c));
}
@@ -466,7 +502,7 @@
VG_(memcpy)(p, block, nbytes); p += nbytes;
* ((UChar*)p) = 1; /*isEnd*/ p += sizeof(UChar);
- vg_assert(p - pstart == bytesReqd);
+ vg_assert( (SizeT)(p - pstart) == bytesReqd);
vg_assert( &gx->payload[bytesReqd]
== ((UChar*)gx) + sizeof(GExpr) + bytesReqd );
@@ -493,7 +529,7 @@
init_Cursor( &loc, cc->debug_loc_img,
cc->debug_loc_sz, 0, cc->barf,
"Overrun whilst reading .debug_loc section(2)" );
- set_position_of_Cursor( &loc, (Word)debug_loc_offset );
+ set_position_of_Cursor( &loc, debug_loc_offset );
/* Who frees this xa? It is freed before this fn exits. */
xa = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
@@ -610,7 +646,7 @@
init_Cursor( &ranges, cc->debug_ranges_img,
cc->debug_ranges_sz, 0, cc->barf,
"Overrun whilst reading .debug_ranges section(2)" );
- set_position_of_Cursor( &ranges, (Word)debug_ranges_offset );
+ set_position_of_Cursor( &ranges, debug_ranges_offset );
/* Who frees this xa? varstack_preen() does. */
xa = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
@@ -1177,8 +1213,8 @@
Int ctsSzB;
UWord ctsMemSzB;
- Word saved_die_c_offset = get_position_of_Cursor( c_die );
- Word saved_abbv_c_offset = get_position_of_Cursor( c_abbv );
+ UWord saved_die_c_offset = get_position_of_Cursor( c_die );
+ UWord saved_abbv_c_offset = get_position_of_Cursor( c_abbv );
varstack_preen( parser, td3, level );
@@ -1238,6 +1274,8 @@
invalid, and we can legitimately stop and complain. */
}
#else
+ /* .. whereas The Reality is, simply assume the SVMA is zero
+ if it isn't specified. */
if (level == 0) {
vg_assert(!cc->cu_svma_known);
cc->cu_svma_known = True;
@@ -1415,7 +1453,7 @@
? "<anon_variable>"
: "<anon_formal>", -1 );
- /* If this is a local variable (non-external), try to find
+ /* If this is a local variable (non-external), try to find
the GExpr for the DW_AT_frame_base of the containing
function. It should have been pushed on the stack at the
time we encountered its DW_TAG_subprogram DIE, so the way
@@ -1437,10 +1475,12 @@
}
}
if (!found) {
- VG_(printf)(
- "parse_var_DIE: found non-external variable "
- "outside DW_TAG_subprogram\n");
- // FIXME goto bad_DIE;
+ if (VG_(clo_verbosity) >= 0) {
+ VG_(message)(Vg_DebugMsg,
+ "warning: parse_var_DIE: non-external variable "
+ "outside DW_TAG_subprogram");
+ }
+ // FIXME goto bad_DIE;
}
}
@@ -1507,7 +1547,7 @@
DW_AT_type : <13e>
<2><2c3>: Abbrev Number: 13 (DW_TAG_formal_parameter)
DW_AT_type : <133>
- */
+ */
/* ignore */
}
else
@@ -1601,7 +1641,7 @@
typedef
struct {
/* What source language? 'C'=C/C++, 'F'=Fortran, '?'=other
- Established once per compilation unit. */
+ Established once per compilation unit. */
UChar language;
/* A stack of types which are currently under construction */
Int sp; /* [sp] is innermost active entry; sp==-1 for empty
@@ -1710,8 +1750,8 @@
D3Expr* expr = NULL;
TyBounds* bounds = NULL;
- Word saved_die_c_offset = get_position_of_Cursor( c_die );
- Word saved_abbv_c_offset = get_position_of_Cursor( c_abbv );
+ UWord saved_die_c_offset = get_position_of_Cursor( c_die );
+ UWord saved_abbv_c_offset = get_position_of_Cursor( c_abbv );
/* If we've returned to a level at or above any previously noted
parent, un-note it, so we don't believe we're still collecting
@@ -2354,9 +2394,6 @@
}
case TyA_Type: {
UChar enc;
-#if 0
- Word i;
-#endif
XArray* xa;
Type* ty = (Type*)adp->payload;
switch (ty->tag) {
@@ -2399,30 +2436,10 @@
|| ty->Ty.Enum.szB < 1
|| ty->Ty.Enum.szB > 8) goto baaad;
xa = ty->Ty.Enum.atomRs;
-#if 0
- for (i = 0; i < VG_(sizeXA)(xa); i++) {
- void** ppAtom = VG_(indexXA)(xa,i);
- ok = resolve_binding( &payload, map,
- *ppAtom, D3TyA_Atom,
- False/*!allow_invalid*/ );
- if (!ok) goto baaad;
- *ppAtom = payload;
- }
-#endif
break;
case Ty_StOrUn:
xa = ty->Ty.StOrUn.fields;
if (!xa) goto baaad;
-#if 0
- for (i = 0; i < VG_(sizeXA)(xa); i++) {
- void** ppField = VG_(indexXA)(xa,i);
- ok = resolve_binding( &payload, map,
- *ppField, D3TyA_Field,
- False/*!allow_invalid*/ );
- if (!ok) goto baaad;
- *ppField = payload;
- }
-#endif
break;
case Ty_Fn:
break;
@@ -2458,8 +2475,11 @@
payload = NULL;
ok = resolve_binding( &payload, map, vars->typeR,
TyA_Type, True/*allow_invalid*/ );
-//if (!ok) VG_(printf)("Can't resolve type reference 0x%lx\n", (UWord)vars->typeR);
-//vg_assert(ok);
+
+ if (0 && !ok)
+ VG_(printf)("Can't resolve type reference 0x%lx\n",
+ (UWord)vars->typeR);
+ //vg_assert(ok);
vars->typeR = payload;
}
@@ -2481,8 +2501,8 @@
ULong atag, abbv_code;
UWord posn;
UInt has_children;
- Word start_die_c_offset, start_abbv_c_offset;
- Word after_die_c_offset, after_abbv_c_offset;
+ UWord start_die_c_offset, start_abbv_c_offset;
+ UWord after_die_c_offset, after_abbv_c_offset;
/* --- Deal with this DIE --- */
posn = get_position_of_Cursor( c );
@@ -2779,7 +2799,7 @@
TRACE_D3("\n------ Parsing .debug_info section ------\n");
while (True) {
- Word cu_start_offset, cu_offset_now;
+ UWord cu_start_offset, cu_offset_now;
CUConst cc;
if (is_at_end_Cursor( &info ))
break;
Modified: branches/DATASYMS/coregrind/m_debuginfo/readelf.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/readelf.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/readelf.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -1152,7 +1152,8 @@
/* Make sure the PT_LOADable entries are in order */
if (phdr->p_type == PT_LOAD) {
- TRACE_SYMTAB("PT_LOAD in order?: %p %p\n", prev_svma, phdr->p_vaddr);
+ TRACE_SYMTAB("PT_LOAD in order?: %p %p\n",
+ prev_svma, phdr->p_vaddr);
if (phdr->p_vaddr < prev_svma) {
ML_(symerr)(di, True,
"ELF Program Headers are not in ascending order");
Modified: branches/DATASYMS/coregrind/m_debuginfo/storage.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/storage.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/storage.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -708,6 +708,39 @@
vg_assert(type);
vg_assert(gexpr);
+ /* Ignore any variables whose aMin .. aMax (that is, range of text
+ addresses for which they actually exist) falls outside the text
+ segment. Is this indicative of a bug in the reader? Maybe. */
+ if (di->text_size > 0
+ && level > 0
+ && (aMax < di->text_avma
+ || aMin >= di->text_avma + di->text_size)) {
+ if (VG_(clo_verbosity) >= 0) {
+ VG_(message)(Vg_DebugMsg,
+ "warning: addVar: in range %p .. %p outside "
+ "segment %p .. %p (%s)",
+ aMin, aMax,
+ di->text_avma, di->text_avma + di->text_size -1,
+ name
+ );
+ }
+ return;
+ }
+
+ /* If the type's size is zero (which can mean unknown size), ignore
+ it. We will never be able to actually relate a data address to
+ a data object with zero size, so there's no point in storing
+ info on it. */
+ if (ML_(sizeOfType)(type) == 0) {
+ if (VG_(clo_verbosity) >= 0) {
+ VG_(message)(Vg_DebugMsg,
+ "warning: addVar: zero or unknown size (%s)",
+ name
+ );
+ }
+ return;
+ }
+
if (!di->varinfo) {
di->varinfo = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
sizeof(OSet*) );
@@ -726,7 +759,9 @@
VG_(addToXA)( di->varinfo, &scope );
/* Add a single range covering the entire address space. At
level 0 we require this doesn't get split. At levels above 0
- we require that any additions to it cause it to get split. */
+ we require that any additions to it cause it to get split.
+ All of these invariants get checked both add_var_to_arange
+ and after reading is complete, in canonicaliseVarInfo. */
nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
vg_assert(nyu);
nyu->aMin = (Addr)0;
@@ -1162,8 +1197,8 @@
static void canonicaliseCFI ( struct _DebugInfo* di )
{
Int i, j;
- const Addr minAddr = 0;
- const Addr maxAddr = ~minAddr;
+ const Addr minAvma = 0;
+ const Addr maxAvma = ~minAvma;
/* Note: take care in here. di->cfsi can be NULL, in which
case _used and _size fields will be zero. */
@@ -1172,23 +1207,23 @@
vg_assert(di->cfsi_size == 0);
}
- /* Set cfsi_minaddr and cfsi_maxaddr to summarise the entire
+ /* Set cfsi_minavma and cfsi_maxavma to summarise the entire
address range contained in cfsi[0 .. cfsi_used-1]. */
- di->cfsi_minaddr = maxAddr;
- di->cfsi_maxaddr = minAddr;
+ di->cfsi_minavma = maxAvma;
+ di->cfsi_maxavma = minAvma;
for (i = 0; i < (Int)di->cfsi_used; i++) {
Addr here_min = di->cfsi[i].base;
Addr here_max = di->cfsi[i].base + di->cfsi[i].len - 1;
- if (here_min < di->cfsi_minaddr)
- di->cfsi_minaddr = here_min;
- if (here_max > di->cfsi_maxaddr)
- di->cfsi_maxaddr = here_max;
+ if (here_min < di->cfsi_minavma)
+ di->cfsi_minavma = here_min;
+ if (here_max > di->cfsi_maxavma)
+ di->cfsi_maxavma = here_max;
}
if (di->trace_cfi)
VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n",
di->cfsi_used,
- di->cfsi_minaddr, di->cfsi_maxaddr);
+ di->cfsi_minavma, di->cfsi_maxavma);
/* Sort the cfsi array by base address. */
VG_(ssort)(di->cfsi, di->cfsi_used, sizeof(*di->cfsi), compare_DiCfSI);
@@ -1223,9 +1258,9 @@
/* No zero-length ranges. */
vg_assert(di->cfsi[i].len > 0);
/* Makes sense w.r.t. summary address range */
- vg_assert(di->cfsi[i].base >= di->cfsi_minaddr);
+ vg_assert(di->cfsi[i].base >= di->cfsi_minavma);
vg_assert(di->cfsi[i].base + di->cfsi[i].len - 1
- <= di->cfsi_maxaddr);
+ <= di->cfsi_maxavma);
if (i < di->cfsi_used - 1) {
/*
Modified: branches/DATASYMS/coregrind/m_debuginfo/tytypes.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/tytypes.c 2008-02-17 18:51:06 UTC (rev 7420)
+++ branches/DATASYMS/coregrind/m_debuginfo/tytypes.c 2008-02-17 20:54:12 UTC (rev 7421)
@@ -360,6 +360,7 @@
Word i;
switch (ty->tag) {
case Ty_Base:
+ vg_assert(ty->Ty.Base.szB > 0);
return ty->Ty.Base.szB;
case Ty_Qual:
return ML_(sizeOfType)( ty->Ty.Qual.typeR );
@@ -425,7 +426,7 @@
Word i;
GXResult res;
TyField *field = NULL, *fields;
- SizeT offMin = 0, offMax1 = 0;
+ OffT offMin = 0, offMax1 = 0;
if (!ty->Ty.StOrUn.isStruct) goto done;
fields = ty->Ty.StOrUn.fields;
if ((!fields) || VG_(sizeXA)(fields) == 0) goto done;
|
|
From: Bart V. A. <bar...@gm...> - 2008-02-17 19:39:39
|
Hello Julian, While browsing through the Helgrind documentation, I found the following item in the to do list: * Document races caused by gcc's thread-unsafe code generation for speculative stores. In the interim see http://gcc.gnu.org/ml/gcc/2007-10/msg00266.html and http://lkml.org/lkml/2007/10/24/673. This item may be removed from the to do list: the discussion on the gcc and LKML mailing lists has been closed with the conclusion that speculative stores may not introduce data races in multithreaded programs. This is also what is specified in the draft C++0x memory model (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2338.html). Ian Lance Taylor has developed and checked in a patch that fixes the erroneous gcc behavior (http://gcc.gnu.org/ml/gcc/2007-10/msg00554.html). It might be appropriate however to add a note about which gcc versions can introduce such erroneous behavior. Bart. |
|
From: <sv...@va...> - 2008-02-17 18:51:05
|
Author: bart Date: 2008-02-17 18:51:06 +0000 (Sun, 17 Feb 2008) New Revision: 7420 Log: Rewrote the README.txt document. Modified: trunk/exp-drd/docs/README.txt Modified: trunk/exp-drd/docs/README.txt =================================================================== --- trunk/exp-drd/docs/README.txt 2008-02-17 18:13:00 UTC (rev 7419) +++ trunk/exp-drd/docs/README.txt 2008-02-17 18:51:06 UTC (rev 7420) @@ -1,51 +1,120 @@ DRD: a Data Race Detector ========================= -Last update: December 3, 2007 by Bart Van Assche. +Last update: February 16, 2008 by Bart Van Assche. -The Difficulty of Multithreading Programming --------------------------------------------- -Multithreading is a concept to model multiple concurrent activities within a -single process. Since the invention of the multithreading concept, there is an -ongoing debate about which way to model concurrent activities is better -- -multithreading or message passing. This debate exists because -multithreaded programming is error prone: multithreaded programs can exhibit -data races and/or deadlocks. Despite these risks multithreaded programming is -popular: for many applications multithreading is a more natural programming -style, and multithreaded code often runs faster than the same application -implemented via message passing. +Introduction +------------ -In the context of DRD, a data race is defined as two concurrent memory -accesses, where at least one of these two memory accesses is a store operation, -and these accesses are not protected by proper locking constructs. Data -races are harmful because these may lead to unpredictable results in -multithreaded programs. There is a general consensus that data races -should be avoided in multithreaded programs. +Multithreading is a concept to model multiple concurrent activities +within a single process. Each such concurrent activity is called a +thread. All threads that are active within a process share the same +set of memory locations. Data is exchanged between threads by writing +to and reading from the shared memory. Since the invention of the +multithreading concept, there is an ongoing debate about which way to +model concurrent activities is better -- shared memory programming or +message passing [Ousterhout 1996]. This debate exists because each +model has significant advantages and disadvantages. While shared +memory programming relieves the programmer from writing code for the +exchange of data between concurrent activities and while shared memory +programming has a performance advantage over message passing, shared +memory programming is error prone. Shared memory programs can exhibit +data races and/or deadlocks. Data races are harmful because these may +lead to unpredictable results and nondeterministic behavior in +multithreaded programs. There are two ways to detect data races and +deadlocks: static analysis and runtime detection by a tool. Since +there do not yet exist any tools that can carry out static analysis of +data races or deadlocks, the only option to statically detect such +anomolies is source reading by a human. It takes a huge effort however +to detect all possible data races or deadlocks via source +reading. This is why tools for detecting data races and deadlocks at +runtime are essential. +Data Races +---------- + +Threads in a multithreaded process exchange information by writing to +and reading from memory locations shared by the threads. Two accesses +to the same memory location by different threads are called +conflicting accesses if at least one of these two accesses modifies +the contents of the memory location. + +A deterministic exchange of data between threads is only possible if +conflicting accesses happen in a well-defined order. It is the role of +synchronization actions to enforce the runtime execution order of +conflicting accesses. Examples of such synchronization actions are +pthread_mutex_lock(), pthread_mutex_unlock(), sem_wait(), sem_post(), +... + +An important concept with regard to the ordering of load and store +operations on shared memory is the happens-before-1 relation or hb1 +[Adve 1991]. The hb1 relation is a partial order defined over all +shared memory operations. The hb1 relation includes both the +intrathread execution order and the interthread ordering imposed by +synchronization operations. All intrathread accesses of a single +thread are totally ordered by hb1. Since hb1 is a partial order for +interthread memory accesses, interthread memory accesses are either +ordered or not ordered by hb1. A data race is defined by Adve et +al. as two conflicting accesses that are not ordered by the +happens-before-1 relation. Or: which accesses are considered as data +races depends on the runtime behavior of a program. + +There is an interesting relationship between runtime behavior and +multithreaded design patterns. The most straightforward way to ensure +that different threads access shared data in an orderly fashion is to +ensure that at most one thread can access the object at any given +time. This can be realized by a programmer to surround all shared data +accesses with calls to proper synchronization functions. Such a source +code strategy for avoiding data races is also called a locking +discipline. An important property of programs that follow this +strategy is that these programs are data-race free. + +There exist two kinds of tools for verifying the runtime behavior of +multithreaded programs. One class of tools verifies a locking +strategy, and another class of tools verifies the absence of data +races. The difference is subtle but important. + +The most well know algorithm for runtime verification of a locking +strategy is the so called Eraser algorithm [Savage 1997]. While this +algorithm allows to catch more programming errors than the conflicting +accesses classified as data races by the definition of Sarita Adve et +al., unfortunately the Eraser algorithm also reports a lot of false +positives. It is tedious to review the output of the Eraser tool +manually and to verify which reported pairs of accesses are false +positives and which pairs are real data races. There is still research +ongoing about how to reduce the number of false positives reported by +the Eraser algorithm -- see e.g. [Müehlenfeld 2007]. The Helgrind +tool is a refinement of the Eraser algorithm. + +A second class of data race detection tools detects all conflicting +accesses that are data races according to the definition of Sarita +Adve et al. While in theory there is no guarantee that these tools +detect all locking discipline violations, these tools do not report +false positives. These tools are the most practical tools to +use. Examples of this class of tools are DIOTA [Ronsse 2004], Intel(R) +Thread Checker [Banerjee 2006a, Banerjee 2006b, Sack 2006] and DRD. + + About DRD --------- -The current version of DRD is able to perform data race detection on small -programs -- DRD quickly runs out of memory for realistically sized programs. -The current version runs well under Linux on x86 CPU's for multithreaded -programs that use the POSIX threading library. Regular POSIX threads, detached -threads, mutexes, condition variables and spinlocks are supported. POSIX -semaphores, barriers and reader-writer locks are not yet supported. -Extensive scientific research has been carried out on the area of data-race -detection. The two most important algorithms are known as the Eraser algorithm -and the algorithm based on the happens-before relationship, first documented by -Netzer. The Eraser algorithm can result in false positives, while the Netzer -algorithm guarantees not to report false positives. The Netzer algorithm -ignores a certain class of data races however. Both algorithms have been -implemented in Valgrind. The helgrind tool implements the Eraser algorithm, -and the DRD tool implements the Netzer algorithm. Although [Savage 1997] -claims that the Netzer algorithm is harder to implement efficiently, as of -version 3.3.0 drd runs significantly faster on several regression tests than -helgrind. +DRD is still under development, that is why the tool is named exp-drd. +The current version of DRD is able to perform data race detection on +small programs -- DRD quickly runs out of memory for realistically +sized programs. The current version runs well under Linux on x86 +CPU's for multithreaded programs that use the POSIX threading +library. Regular POSIX threads, detached threads, mutexes, condition +variables, spinlocks, semaphores and barriers are supported. POSIX +reader-writer locks are not yet supported. +Although [Savage 1997] claims that a happens-before detector is harder +to implement efficiently than the Eraser algorithm, as of Valgrind +version 3.3.0 exp-drd runs significantly faster on several regression +tests than Helgrind. + How to use DRD -------------- To use this tool, specify --tool=drd on the Valgrind command line. @@ -54,30 +123,114 @@ Future DRD Versions ------------------- The following may be expected in future versions of DRD: -* More extensive documentation. * Drastically reduced memory consumption, such that realistic applications can be analyzed with DRD. * Faster operation. -* Support for semaphores, barriers and reader-writer locks. +* More extensive documentation. +* Support for reader-writer locks. * Support for PowerPC CPU's. * A lock dependency analyzer, as a help in deadlock prevention. -* Support for more than 256 mutexes per process. +* Elimination of several artificial limitations. -See also --------- -* Robert H. B. Netzer and Barton P. Miller. What are race - conditions? Some issues and formalizations. ACM Letters 136 - on Programming Languages and Systems, 1(1):74–88, March 1992. - -* John Ousterhout, Why Threads Are A Bad Idea (for most - purposes), Invited Talk at the 1996 USENIX Technical Conference (January - 25, 1996). http://home.pacbell.net/ouster/threads.pdf - -* Stefan Savage, Michael Burrows, Greg Nelson, Patrick - Sobalvarro and Thomas Anderson, Eraser: A Dynamic Data Race Detector for - Multithreaded Programs, ACM Transactions on Computer Systems, - 15(4):391-411, November 1997. +References +---------- +[Lamport 1978] + Leslie Lamport. + Time, clocks, and the ordering of events in a distributed system. + Communications of the ACM archive, Volume 21, Issue 7, 1978. + http://research.microsoft.com/users/lamport/pubs/time-clocks.pdf + http://portal.acm.org/citation.cfm?id=359563 +[Netzer 1992] + Robert H. B. Netzer and Barton P. Miller. + What are race conditions? Some issues and formalizations. + ACM Letters on Programming Languages and Systems, 1(1):74–88, March 1992. + http://www.securitytechnet.com/resource/security/os/race-conditions.pdf + http://portal.acm.org/citation.cfm?id=130623 +[Adve 1991] + Sarita V. Adve, Mark D. Hill, Barton P. Miller, Robert H. B. Netzer. + Detecting data races on weak memory systems. + Proceedings of the 18th annual international symposium on Computer + architecture, Toronto, Ontario, Canada, pp 234-243, 1991. + http://rsim.cs.uiuc.edu/~sadve/Publications/isca91.dataraces.ps + http://portal.acm.org/citation.cfm?doid=115953.115976 + +[Ousterhout 1996] + John Ousterhout. + Why Threads Are A Bad Idea (for most purposes). + Invited Talk at the 1996 USENIX Technical Conference (January 25, 1996). + http://home.pacbell.net/ouster/threads.pdf + +[Savage 1997] + Stefan Savage, Michael Burrows, Greg Nelson, Patrick Sobalvarro and + Thomas Anderson. + Eraser: A Dynamic Data Race Detector for Multithreaded Programs. + ACM Transactions on Computer Systems, 15(4):391-411, November 1997. + http://www.cs.ucsd.edu/users/savage/papers/Tocs97.pdf + http://portal.acm.org/citation.cfm?id=265927 + +[Ronsse 1999] + Michiel Ronsse, Koen De Bosschere. + RecPlay: a fully integrated practical record/replay system. + ACM Transactions on Computer Systems (TOCS), Volume 17, Issue 2 (May 1999), + pp. 133-152, 1999. + http://portal.acm.org/citation.cfm?id=312214 + +[Ronsse 2004] + Michiel Ronsse, Jonas Maebe, Koen De Bosschere. + Detecting Data Races in Sequential Programs with DIOTA. + Proceedings of the 10th International Euro-Par Conference, Springer-Verlag, + Lecture Notes in Computer Science, pp. 82-89, 2004. + http://escher.elis.ugent.be/publ/Edocs/DOC/P104_076.pdf + +[Banerjee 2006a] + Utpal Banerjee, Brian Bliss, Zhiqiang Ma, Paul Petersen. + Unraveling Data Race Detection in the Intel® Thread Checker. + First Workshop on Software Tools for Multi-core Systems (STMCS), in + conjunction with IEEE/ACM International Symposium on Code Generation and + Optimization (CGO), March 26, 2006, Manhattan, New York, NY. + +[Banerjee 2006b] + Utpal Banerjee, Brian Bliss, Zhiqiang Ma, Paul Petersen. + A theory of data race detection + Proceeding of the 2006 workshop on Parallel and distributed systems: testing + and debugging, Portland, Maine, USA, pp. 69-78, 2006. + http://www.cs.ucsb.edu/~tiwari/papers/threadchecker06 + http://portal.acm.org/citation.cfm?id=1147416 + +[Lu 2006] + Shan Lu, Joseph Tucek, Feng Qin, Yuanyuan Zhou. + AVIO: detecting atomicity violations via access interleaving invariants. + Proceedings of the 12th international conference on Architectural support + for programming languages and operating systems, San Jose, California, USA, + pp. 37-48, 2006. + http://www.cse.ohio-state.edu/~qin/pub-papers/2006andbefore/asplos062-lu.pdf + http://portal.acm.org/citation.cfm?id=1168864 + +[Sack 2006] + Paul Sack, Brian E. Bliss, Zhiqiang Ma, Paul Petersen, Josep Torrellas + Accurate and efficient filtering for the Intel thread checker race detector. + Proceedings of the 1st workshop on Architectural and system support for + improving software dependability, San Jose, California, pp. 34-41, 2006. + http://iacoma.cs.uiuc.edu/iacoma-papers/asid06.pdf + http://portal.acm.org/citation.cfm?id=1181309.1181315 + +[Müehlenfeld 2007] + Arndt Müehlenfeld, Franz Wotawa. + Fault detection in multi-threaded c++ server applications. + Proceedings of the 12th ACM SIGPLAN symposium on Principles and practice of + parallel programming, San Jose, California, USA, poster session, + pp. 142-143, 2007. + http://valgrind.org/docs/muehlenfeld2006.pdf + http://portal.acm.org/citation.cfm?id=1229457 + +[Zhou 2007] + Pin Zhou, Radu Teodorescu, Yuanyuan Zhou. + HARD: Hardware-Assisted Lockset-based Race Detection. + Proceedings of the 2007 IEEE 13th International Symposium on High + Performance Computer Architecture, pp. 121-132, 2007. + http://opera.cs.uiuc.edu/paper/Hard-HPCA07.pdf + http://portal.acm.org/citation.cfm?id=1317533.1318108 |
|
From: <sv...@va...> - 2008-02-17 18:12:59
|
Author: bart Date: 2008-02-17 18:13:00 +0000 (Sun, 17 Feb 2008) New Revision: 7419 Log: Updated to do list. Modified: trunk/exp-drd/TODO.txt Modified: trunk/exp-drd/TODO.txt =================================================================== --- trunk/exp-drd/TODO.txt 2008-02-17 11:46:58 UTC (rev 7418) +++ trunk/exp-drd/TODO.txt 2008-02-17 18:13:00 UTC (rev 7419) @@ -1,40 +1,43 @@ -Last updated February 22, 2006 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Last updated February 17, 2008 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Data-race detection algorithm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - pthread rwlock state tracking and support. +- Eliminate the upper bounds on the number of mutexes, condition variables, + semaphores, barriers and threads by converting arrays into OSet's. - Implement segment merging, such that the number of segments per thread remains limited even when there is no synchronization between threads. +- Discuss on the Valgrind mailing list how to make it possible to call + POSIX thread synchronization primitives from client code (drd_intercepts.c) + without triggering Valgrind's redirection mechanism. - Find out why a race is reported on std::string::string(std::string const&) (stc test case 16). -- Eliminate the upper bounds on the number of mutexes, condition variables, - semaphores and barriers by converting arrays into OSet's. - Add a regression test for pthread_mutex_timedlock(). - Find a way for suppressing races on _IO_2_1_stdout (this race is triggered by calling printf() from more than one thread). - Performance testing and tuning. - testing on PPC and AIX (current implementation is only tested on X86 and AMD64). -- Change s_threadinfo[] from an array into an OSet or VgHashTable, in order to - make ThreadId <> DrdThreadId <> pthread_t conversions faster. - [AMD64] Find out why removing 'write(1, "", 0)' in drd_intercepts.c triggers - a crash on AMD64. Is this a drd or a VEX bug ? + a crash on AMD64. Is this an exp-drd or a VEX bug ? +- On x86 and amd64 platforms, add support for implicit locking arising from + the use of the LOCK instruction prefix. + Testing ~~~~~~~ - testing with more complex multithreaded test programs. -- test drd's performance with the SPLASH-2 software, e.g. fft +- test exp-drd's performance with the SPLASH-2 software, e.g. fft (http://www-flash.stanford.edu/apps/SPLASH/). -- Add helgrind's unit tests to drd's unit test set by adding soft links - under drd/tests to the respective helgrind unit tests. +- Add more Helgrind regression tests to exp-drd's regression test set by adding + soft links under exp-drd/tests to the respective Helgrind unit tests. Documentation ~~~~~~~~~~~~~ -- Document how to use the tool. -- Document the code. +- Document the command-line options of the exp-drd tool. Known bugs |
|
From: Bart V. A. <bar...@gm...> - 2008-02-17 16:25:04
|
On Feb 17, 2008 11:35 AM, Markus Schiltknecht <ma...@bl...> wrote: > Hm.. that's a point. But using mainly shared memory for inter process > communication, this won't help, because there's no (or only few) system > calling involved. So the scheduling might very well differ. Regarding sharing memory between processes: record/replay techniques for multithreaded processes are well known and have been documented. The challenge with memory that is shared between processes is how to share the recorded event data between the processes. > I'm also unclear on how easy it would be to "construct" the wanted > situations. Especially if the underlying code changes, so that the > issued system calls suddenly don't match the recorded ones anymore. I'm not sure that it is possible to develop record/replay techniques when different binaries are involved during the record and the replay phase. Bart. |
|
From: Peter A J. <pj...@lu...> - 2008-02-17 15:42:06
|
> So I'm inclined to declare RHL9 as the new oldest-supported-distro > for the trunk, which means we can drop support for LinuxThreads, > gcc < 3.0, and stabs. The stabs support might be useful for other compilers, pcc only supports stabs for example. Regards, Peter |
|
From: Julian S. <js...@ac...> - 2008-02-17 12:09:40
|
> > So what's the oldest commonly-used distro that supported NPTL? > > RH9 is pretty much the first distro to support it isn't it? Yes. According to Ulrich Drepper "RHL9 was the first with NPTL and it served as the basis for RHEL3". So I'm inclined to declare RHL9 as the new oldest-supported-distro for the trunk, which means we can drop support for LinuxThreads, gcc < 3.0, and stabs. J |
|
From: <sv...@va...> - 2008-02-17 11:46:56
|
Author: sewardj
Date: 2008-02-17 11:46:58 +0000 (Sun, 17 Feb 2008)
New Revision: 7418
Log:
Comment-only changes.
Modified:
trunk/helgrind/hg_wordfm.c
trunk/helgrind/hg_wordfm.h
Modified: trunk/helgrind/hg_wordfm.c
===================================================================
--- trunk/helgrind/hg_wordfm.c 2008-02-17 09:21:05 UTC (rev 7417)
+++ trunk/helgrind/hg_wordfm.c 2008-02-17 11:46:58 UTC (rev 7418)
@@ -544,7 +544,9 @@
the set are ordered according to the ordering specified by kCmp,
which becomes obvious if you use VG_(initIterFM),
VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over
- sections of the map, or the whole thing. */
+ sections of the map, or the whole thing. If kCmp is NULL then the
+ ordering used is unsigned word ordering (UWord) on the key
+ values. */
WordFM* HG_(newFM) ( void* (*alloc_nofail)( SizeT ),
void (*dealloc)(void*),
Word (*kCmp)(UWord,UWord) )
Modified: trunk/helgrind/hg_wordfm.h
===================================================================
--- trunk/helgrind/hg_wordfm.h 2008-02-17 09:21:05 UTC (rev 7417)
+++ trunk/helgrind/hg_wordfm.h 2008-02-17 11:46:58 UTC (rev 7418)
@@ -57,13 +57,25 @@
//--- Public interface ---//
//------------------------------------------------------------------//
+/* As of r7409 (15 Feb 08), all these word-based abstractions (WordFM,
+ WordSet, WordBag) now operate on unsigned words (UWord), whereas
+ they previously operated on signed words (Word). This became a
+ problem, when using unboxed comparisons (when kCmp == NULL), with
+ the introduction of HG_(initIterAtFM), which allows iteration over
+ parts of mappings. Iterating over a mapping in increasing order of
+ signed Word keys is not what callers expect when iterating through
+ maps whose keys represent addresses (Addr) since Addr is unsigned,
+ and causes logical problems and assertion failures. */
+
typedef struct _WordFM WordFM; /* opaque */
/* Allocate and initialise a WordFM. If kCmp is non-NULL, elements in
the set are ordered according to the ordering specified by kCmp,
which becomes obvious if you use VG_(initIterFM),
VG_(initIterAtFM), VG_(nextIterFM), VG_(doneIterFM) to iterate over
- sections of the map, or the whole thing. */
+ sections of the map, or the whole thing. If kCmp is NULL then the
+ ordering used is unsigned word ordering (UWord) on the key
+ values. */
WordFM* HG_(newFM) ( void* (*alloc_nofail)( SizeT ),
void (*dealloc)(void*),
Word (*kCmp)(UWord,UWord) );
|
|
From: Markus S. <ma...@bl...> - 2008-02-17 10:38:28
|
Hi,
Bart Van Assche wrote:
> I think that it is possible to implement a record/replay tool for
> multiple processes without modifying the Valgrind scheduler. During
> the recording phase you can gather information about any event that
> influences interprocess ordering by intercepting system calls like
> recv(), send(), sendto(), kill(), ... During the replay phase you can
> intercept the same system calls and delay their execution in such a
> way that scheduling during replay matches scheduling during the
> recording phase.
Hm.. that's a point. But using mainly shared memory for inter process
communication, this won't help, because there's no (or only few) system
calling involved. So the scheduling might very well differ.
I'm also unclear on how easy it would be to "construct" the wanted
situations. Especially if the underlying code changes, so that the
issued system calls suddenly don't match the recorded ones anymore.
But yeah, extending that scheme to not only system calls, but also
events like entering a function or hitting a trace point could help.
Coupled with a loose recording definition, more event based, like:
- after entering function foo execute until syscall signal() is
issued, then interrupt the process (thread) until condition bar
is reached.
These are the kinds of rules which would allow me to specifically test
certain situations which a natural scheduler reaches only very rarely,
but could lead to an error.
Thanks for making me think more about record/replay, looks like I should
investigate somewhat more on what exists in that area.
Regards
Markus
|
|
From: Bart V. A. <bar...@gm...> - 2008-02-17 10:20:00
|
On Feb 17, 2008 11:05 AM, Markus Schiltknecht <ma...@bl...> wrote: > However, what bugs me more is, that there would need to be an interface > to valgrind, to control the internal scheduler (to be able to start and > stop threads or processes based on some external events). I think that it is possible to implement a record/replay tool for multiple processes without modifying the Valgrind scheduler. During the recording phase you can gather information about any event that influences interprocess ordering by intercepting system calls like recv(), send(), sendto(), kill(), ... During the replay phase you can intercept the same system calls and delay their execution in such a way that scheduling during replay matches scheduling during the recording phase. Bart. |
|
From: Markus S. <ma...@bl...> - 2008-02-17 10:08:53
|
Hi, Nicholas Nethercote wrote: > Valgrind really only does intra-process simulation/emulation. It seems > to me you'd need something that simulates/emulates multiple processes. > Maybe a whole system simulator of some kind -- Bochs or SimICS? Yes, I'm partly working with system virtualization for the mentioned testing I'm doing. I prefer qemu or kvm over xen and bochs, but they all offer about the same: they simulate a full system. That's too much and therefore often too complex to setup (you need harddisks, a LiveCD or a root NFS mount, from which your virtual system can start from. All of which are troublesome to setup. And they often require root privileges and are tied to a certain OS). I'm just asking myself: if valgrind can handle multiple threads, why shouldn't it also handle multiple processes? Granted, you'd need to setup some sharded memory or something to be able to do IPC between these valgrind processes. However, what bugs me more is, that there would need to be an interface to valgrind, to control the internal scheduler (to be able to start and stop threads or processes based on some external events). Regards Markus |
|
From: Bart V. A. <bar...@gm...> - 2008-02-17 09:30:00
|
On Feb 15, 2008 7:49 PM, Julian Seward <js...@ac...> wrote: > A related question is: what is the oldest system that we should > attempt to support? I'd tried to ensure V continues to build and > be usable on a vanilla Red Hat 7.3 (+ gcc 2.96) system, and that's > mostly viable with the profilers and Memcheck, but for the > threading tools it's pretty pointless as neither DRD nor Helgrind > work reasonably with LinuxThreads. Maybe it's a good idea to leave out DRD and Helgrind from the build and from the regression tests on LinuxThreads systems. I can write a configure test to detect LinuxThreads if needed. Bart. |
|
From: <sv...@va...> - 2008-02-17 09:21:04
|
Author: bart
Date: 2008-02-17 09:21:05 +0000 (Sun, 17 Feb 2008)
New Revision: 7417
Log:
Fix exp-drd Fedora 8 tc18_semabuse regression test failure. It is okay to leave out the tl_assert(waited) statement because this statement is only triggered in case sem_post() fails, and sem_post() currently only fails when called on something that is not a semaphore.
Modified:
trunk/exp-drd/drd_semaphore.c
Modified: trunk/exp-drd/drd_semaphore.c
===================================================================
--- trunk/exp-drd/drd_semaphore.c 2008-02-17 00:30:12 UTC (rev 7416)
+++ trunk/exp-drd/drd_semaphore.c 2008-02-17 09:21:05 UTC (rev 7417)
@@ -165,12 +165,15 @@
void semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
const SizeT size, const Bool waited)
{
- /* Note: it is hard to implement the sem_post() wrapper correctly if */
- /* sem_post() can return an error code. The reason is that this would */
- /* require to detect whether sem_post() will fail before sem_post is */
- /* called -- p->vc may only be modified if the sem_post() call will */
- /* succeed. */
- tl_assert(waited);
+ /* Note: it is hard to implement the sem_post() wrapper correctly in */
+ /* case sem_post() returns an error code. This is because handling this */
+ /* case correctly requires restoring the vector clock associated with */
+ /* the semaphore to its original value here. In order to do that without */
+ /* introducing a race condition, extra locking has to be added around */
+ /* each semaphore call. Such extra locking would have to be added in */
+ /* drd_intercepts.c. However, it is hard to implement synchronization */
+ /* in drd_intercepts.c in a portable way without calling already */
+ /* redirected functions. */
}
void semaphore_thread_delete(const DrdThreadId threadid)
|
|
From: Tom H. <th...@cy...> - 2008-02-17 05:14:26
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2008-02-17 03:15:20 GMT 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 == 338 tests, 80 stderr failures, 1 stdout failure, 29 post failures == memcheck/tests/addressable (stderr) memcheck/tests/badjump (stderr) memcheck/tests/describe-block (stderr) memcheck/tests/erringfds (stderr) memcheck/tests/leak-0 (stderr) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-pool-0 (stderr) memcheck/tests/leak-pool-1 (stderr) memcheck/tests/leak-pool-2 (stderr) memcheck/tests/leak-pool-3 (stderr) memcheck/tests/leak-pool-4 (stderr) memcheck/tests/leak-pool-5 (stderr) memcheck/tests/leak-regroot (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/long_namespace_xml (stderr) memcheck/tests/lsframe1 (stderr) memcheck/tests/lsframe2 (stderr) memcheck/tests/malloc_free_fill (stderr) memcheck/tests/match-overrun (stderr) memcheck/tests/noisy_child (stderr) memcheck/tests/partial_load_dflt (stderr) memcheck/tests/partial_load_ok (stderr) memcheck/tests/partiallydefinedeq (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/sigkill (stderr) memcheck/tests/stack_changes (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/mremap (stderr) none/tests/mremap2 (stdout) 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) exp-drd/tests/fp_race (stderr) exp-drd/tests/fp_race2 (stderr) exp-drd/tests/matinv (stderr) exp-drd/tests/pth_barrier (stderr) exp-drd/tests/pth_broadcast (stderr) exp-drd/tests/pth_cond_race (stderr) exp-drd/tests/pth_cond_race2 (stderr) exp-drd/tests/pth_create_chain (stderr) exp-drd/tests/pth_detached (stderr) exp-drd/tests/pth_detached2 (stderr) exp-drd/tests/sem_as_mutex (stderr) exp-drd/tests/sem_as_mutex2 (stderr) exp-drd/tests/sigalrm (stderr) exp-drd/tests/tc17_sembar (stderr) exp-drd/tests/tc18_semabuse (stderr) |
|
From: Tom H. <th...@cy...> - 2008-02-17 04:16:25
|
Nightly build on lloyd ( x86_64, Fedora 7 ) started at 2008-02-17 03:05:17 GMT 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 == 372 tests, 7 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-02-17 03:57:13
|
Nightly build on aston ( x86_64, Fedora Core 5 ) started at 2008-02-17 03:20:07 GMT 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 == 378 tests, 9 stderr failures, 1 stdout failure, 0 post failures == memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/blockfault (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/sem (stderr) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-02-17 03:51:24
|
Nightly build on trojan ( x86_64, Fedora Core 6 ) started at 2008-02-17 03:25:15 GMT 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 == 376 tests, 6 stderr failures, 5 stdout failures, 0 post failures == 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/mremap (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) |
|
From: Tom H. <th...@cy...> - 2008-02-17 03:32:26
|
Nightly build on dellow ( x86_64, Fedora 8 ) started at 2008-02-17 03:10:03 GMT 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 == 372 tests, 9 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) helgrind/tests/tc18_semabuse (stderr) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) exp-drd/tests/tc18_semabuse (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 == 372 tests, 9 stderr failures, 3 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/vcpu_fnfns (stdout) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_cvsimple (stdout) helgrind/tests/tc18_semabuse (stderr) helgrind/tests/tc20_verifywrap (stderr) helgrind/tests/tc22_exit_w_lock (stderr) exp-drd/tests/tc18_semabuse (stderr) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Sun Feb 17 03:21:54 2008 --- new.short Sun Feb 17 03:32:29 2008 *************** *** 8,10 **** ! == 372 tests, 9 stderr failures, 3 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) --- 8,10 ---- ! == 372 tests, 9 stderr failures, 2 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) *************** *** 16,18 **** none/tests/mremap2 (stdout) - none/tests/pth_cvsimple (stdout) helgrind/tests/tc18_semabuse (stderr) --- 16,17 ---- |
|
From: Tom H. <th...@cy...> - 2008-02-17 03:16:16
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2008-02-17 03:00:05 GMT 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 == 378 tests, 29 stderr failures, 3 stdout failures, 0 post failures == memcheck/tests/malloc_free_fill (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (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/mremap (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) |
|
From: <sv...@va...> - 2008-02-17 00:30:18
|
Author: sewardj
Date: 2008-02-17 00:30:12 +0000 (Sun, 17 Feb 2008)
New Revision: 7416
Log:
More tidying up in Dwarf3 variable reading:
* m_debuginfo.c: more all variable-related stuff
further down the file
* m_storage.c: deal properly with code address ranges for variables,
in which the address ranges for which variables exist overlap.
Also, add a new method canonicaliseVarInfo, which doesn't
actually change the data structures, but does walk over them
(when .debug_info reading is complete) to check representational
invariants are being observed.
Modified:
branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h
branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
branches/DATASYMS/coregrind/m_debuginfo/storage.c
branches/DATASYMS/coregrind/m_debuginfo/tytypes.c
Modified: branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/debuginfo.c 2008-02-17 00:30:12 UTC (rev 7416)
@@ -194,6 +194,9 @@
{
Word i, j;
struct strchunk *chunk, *next;
+ TyAdmin *admin1, *admin2;
+ GExpr *gexpr1, *gexpr2;
+
vg_assert(di != NULL);
if (di->filename) ML_(dinfo_free)(di->filename);
if (di->symtab) ML_(dinfo_free)(di->symtab);
@@ -206,37 +209,43 @@
ML_(dinfo_free)(chunk);
}
- { TyAdmin *admin1, *admin2;
- GExpr *gexpr1, *gexpr2;
- for (admin1 = di->tyadmins; admin1; admin1 = admin2) {
- admin2 = admin1->next;
- ML_(delete_TyAdmin_and_payload)(admin1);
- }
- for (gexpr1 = di->gexprs; gexpr1; gexpr1 = gexpr2) {
- gexpr2 = gexpr1->next;
- ML_(dinfo_free)(gexpr1);
- }
+ /* Delete the two admin lists. These lists exist purely so that we
+ can visit each object exactly once when we need to delete
+ them. */
+ for (admin1 = di->admin_tyadmins; admin1; admin1 = admin2) {
+ admin2 = admin1->next;
+ ML_(delete_TyAdmin_and_payload)(admin1);
}
+ for (gexpr1 = di->admin_gexprs; gexpr1; gexpr1 = gexpr2) {
+ gexpr2 = gexpr1->next;
+ ML_(dinfo_free)(gexpr1);
+ }
+ /* Dump the variable info. This is kinda complex: we must take
+ care not to free items which reside in either the admin lists
+ (as we have just freed them) or which reside in the DebugInfo's
+ string table. */
if (di->varinfo) {
for (i = 0; i < VG_(sizeXA)(di->varinfo); i++) {
OSet* scope = *(OSet**)VG_(indexXA)(di->varinfo, i);
if (!scope) continue;
- // iterate over all entries in 'scope'
+ /* iterate over all entries in 'scope' */
VG_(OSetGen_ResetIter)(scope);
while (True) {
DiAddrRange* arange = VG_(OSetGen_Next)(scope);
if (!arange) break;
- // for each var in 'arange'
+ /* for each var in 'arange' */
vg_assert(arange->vars);
for (j = 0; j < VG_(sizeXA)( arange->vars ); j++) {
DiVariable* var = (DiVariable*)VG_(indexXA)(arange->vars,j);
vg_assert(var);
/* Nothing to free in var: all the pointer fields refer
- to stuff either on an admin list, or in .strchunks */
+ to stuff either on an admin list, or in
+ .strchunks */
}
VG_(deleteXA)(arange->vars);
- /* Don't free arange itself, as OSetGen_Destroy does that */
+ /* Don't free arange itself, as OSetGen_Destroy does
+ that */
}
VG_(OSetGen_Destroy)(scope);
}
@@ -999,454 +1008,6 @@
return True;
}
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-/// begin Generate data description from DWARF3 debug info
-
-/* Evaluate the location expression/list for var, to see whether or
- not data_addr falls within the variable. If so also return the
- offset of data_addr from the start of the variable. Note that
- regs, which supplies ip,sp,fp values, will be NULL for global
- variables, and non-NULL for local variables. */
-static Bool data_address_is_in_var ( /*OUT*/UWord* offset,
- DiVariable* var,
- RegSummary* regs,
- Addr data_addr )
-{
- SizeT var_szB;
- GXResult res;
- Bool show = False;
- vg_assert(var->name);
- vg_assert(var->type);
- vg_assert(var->gexpr);
- var_szB = ML_(sizeOfType)(var->type);
-
- if (show) {
- VG_(printf)("VVVV: find loc: %s :: ", var->name );
- ML_(pp_Type_C_ishly)( var->type );
- VG_(printf)("\n");
- }
-
- res = ML_(evaluate_GX)( var->gexpr, var->fbGX, regs );
-
- if (show) VG_(printf)("VVVV: -> 0x%lx %s\n", res.res,
- res.failure ? res.failure : "(success)");
- if (!res.failure && res.res <= data_addr
- && data_addr < res.res + var_szB) {
- *offset = data_addr - res.res;
- return True;
- } else {
- return False;
- }
-}
-
-
-/* Format the acquired information into dname1[0 .. n_dname-1] and
- dname2[0 .. n_dname-1] in an understandable way. Not so easy.
- If frameNo is -1, this is assumed to be a global variable; else
- a local variable. */
-static void format_message ( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
- Addr data_addr,
- DiVariable* var,
- OffT var_offset,
- OffT residual_offset,
- XArray* /*UChar*/ described,
- Int frameNo,
- ThreadId tid )
-{
- Bool have_descr, have_srcloc;
- UChar* vo_plural = var_offset == 1 ? "" : "s";
- UChar* ro_plural = residual_offset == 1 ? "" : "s";
-
- vg_assert(frameNo >= -1);
- vg_assert(dname1 && dname2 && n_dname > 1);
- vg_assert(described);
- vg_assert(var && var->name);
- have_descr = VG_(sizeXA)(described) > 0
- && *(UChar*)VG_(indexXA)(described,0) != '\0';
- have_srcloc = var->fileName && var->lineNo > 0;
-
- dname1[0] = dname2[0] = '\0';
-
- /* ------ local cases ------ */
-
- if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
- /* no srcloc, no description:
- Address 0x7fefff6cf is 543 bytes inside local var "a",
- in frame #1 of thread 1
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside local var \"%s\",",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "in frame #%d of thread %d", frameNo, (Int)tid);
- }
- else
- if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
- /* no description:
- Address 0x7fefff6cf is 543 bytes inside local var "a"
- declared at dsyms7.c:17, in frame #1 of thread 1
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside local var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d, in frame #%d of thread %d",
- var->fileName, var->lineNo, frameNo, (Int)tid);
- }
- else
- if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
- /* no srcloc:
- Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
- in frame #1 of thread 1
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside %s%s",
- data_addr, residual_offset, ro_plural, var->name,
- VG_(indexXA)(described,0) );
- VG_(snprintf)(
- dname2, n_dname,
- "in frame #%d of thread %d", frameNo, (Int)tid);
- }
- else
- if ( frameNo >= 0 && have_srcloc && have_descr ) {
- /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
- declared at dsyms7.c:17, in frame #1 of thread 1 */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- VG_(indexXA)(described,0) );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d, in frame #%d of thread %d",
- var->fileName, var->lineNo, frameNo, (Int)tid);
- }
- else
- /* ------ global cases ------ */
- if ( frameNo >= -1 && (!have_srcloc) && (!have_descr) ) {
- /* no srcloc, no description:
- Address 0x7fefff6cf is 543 bytes inside global var "a"
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside global var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
- }
- else
- if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
- /* no description:
- Address 0x7fefff6cf is 543 bytes inside global var "a"
- declared at dsyms7.c:17
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside global var \"%s\"",
- data_addr, var_offset, vo_plural, var->name );
- VG_(snprintf)(
- dname2, n_dname,
- "declared at %s:%d",
- var->fileName, var->lineNo);
- }
- else
- if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
- /* no srcloc:
- Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
- a global variable
- */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- VG_(indexXA)(described,0) );
- VG_(snprintf)(
- dname2, n_dname,
- "a global variable");
- }
- else
- if ( frameNo >= -1 && have_srcloc && have_descr ) {
- /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
- a global variable declared at dsyms7.c:17 */
- VG_(snprintf)(
- dname1, n_dname,
- "Address 0x%lx is %lu byte%s inside %s%s,",
- data_addr, residual_offset, ro_plural, var->name,
- VG_(indexXA)(described,0) );
- VG_(snprintf)(
- dname2, n_dname,
- "a global variable declared at %s:%d",
- var->fileName, var->lineNo);
- }
- else
- vg_assert(0);
-
- 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
- False. */
-static
-Bool consider_vars_in_frame ( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
- Addr data_addr,
- Addr ip, Addr sp, Addr fp,
- /* shown to user: */
- ThreadId tid, Int frameNo )
-{
- Word i;
- DebugInfo* di;
- RegSummary regs;
-
- static UInt n_search = 0;
- static UInt n_steps = 0;
- n_search++;
-
- /* 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_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 False;
-
- if (0 && ((n_search & 0x1) == 0))
- VG_(printf)("consider_vars_in_frame: %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 False;
-
- /* 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 = sp;
- regs.fp = fp;
-
- /* "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 (!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);
- /* 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. */
- vg_assert(! (arange->aMin == (Addr)0
- && arange->aMax == ~(Addr)0) );
- vars = arange->vars;
- for (j = 0; j < VG_(sizeXA)( vars ); j++) {
- DiVariable* var = (DiVariable*)VG_(indexXA)( vars, j );
- SizeT offset;
- if (data_address_is_in_var( &offset, var, ®s, data_addr )) {
- OffT residual_offset = 0;
- XArray* described = ML_(describe_type)( &residual_offset,
- var->type, offset );
- format_message( dname1, dname2, n_dname,
- data_addr, var, offset, residual_offset,
- described, frameNo, tid );
- VG_(deleteXA)( described );
- return True;
- }
- }
- }
-
- return False;
-}
-
-/* Try to form some description of data_addr by looking at the DWARF3
- debug info we have. This considers all global variables, and all
- frames in the stacks of all threads. Result (or as much as will
- fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
- to be zero terminated. */
-Bool VG_(get_data_description)( /*OUT*/Char* dname1,
- /*OUT*/Char* dname2,
- Int n_dname,
- Addr data_addr )
-{
-# define N_FRAMES 8
- Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
- UInt n_frames;
-
- Addr stack_min, stack_max;
- ThreadId tid;
- Bool found;
- DebugInfo* di;
- Word j;
-
- vg_assert(n_dname > 1);
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
-
- if (0) VG_(printf)("GDD: dataaddr %p\n", data_addr);
-
- /* First, see if data_addr is (or is part of) a global variable.
- Loop over the DebugInfos we have. Check data_addr against the
- outermost scope of all of them, as that should be a global
- scope. */
- for (di = debugInfo_list; di != NULL; di = di->next) {
- OSet* global_scope;
- Int gs_size;
- Addr zero;
- DiAddrRange* global_arange;
- Word i;
- XArray* vars;
-
- /* text segment missing? unlikely, but handle it .. */
- if (di->text_size == 0)
- continue;
- /* any var info at all? */
- if (!di->varinfo)
- continue;
- /* perhaps this object didn't contribute any vars at all? */
- if (VG_(sizeXA)( di->varinfo ) == 0)
- continue;
- global_scope = *(OSet**)VG_(indexXA)( di->varinfo, 0 );
- vg_assert(global_scope);
- gs_size = VG_(OSetGen_Size)( global_scope );
- /* The global scope might be completely empty if this
- compilation unit declared locals but nothing global. */
- if (gs_size == 0)
- continue;
- /* But if it isn't empty, then it must contain exactly one
- element, which covers the entire address range. */
- vg_assert(gs_size == 1);
- /* Fish out the global scope and check it is as expected. */
- zero = 0;
- global_arange
- = VG_(OSetGen_Lookup)( global_scope, &zero );
- /* The global range from (Addr)0 to ~(Addr)0 must exist */
- vg_assert(global_arange);
- vg_assert(global_arange->aMin == (Addr)0
- && global_arange->aMax == ~(Addr)0);
- /* Any vars in this range? */
- if (!global_arange->vars)
- continue;
- /* Ok, there are some vars in the global scope of this
- DebugInfo. Wade through them and see if the data addresses
- of any of them bracket data_addr. */
- vars = global_arange->vars;
- for (i = 0; i < VG_(sizeXA)( vars ); i++) {
- SizeT offset;
- DiVariable* var = (DiVariable*)VG_(indexXA)( vars, i );
- vg_assert(var->name);
- /* Note we use a NULL RegSummary* here. It can't make any
- sense for a global variable to have a location expression
- which depends on a SP/FP/IP value. So don't supply any.
- This means, if the evaluation of the location
- expression/list requires a register, we have to let it
- fail. */
- if (data_address_is_in_var( &offset, var,
- NULL/* RegSummary* */,
- data_addr )) {
- OffT residual_offset = 0;
- XArray* described = ML_(describe_type)( &residual_offset,
- var->type, offset );
- format_message( dname1, dname2, n_dname,
- data_addr, var, offset, residual_offset,
- described, -1/*frameNo*/, tid );
- VG_(deleteXA)( described );
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
- return True;
- }
- }
- }
-
- /* Ok, well it's not a global variable. So now let's snoop around
- in the stacks of all the threads. First try to figure out which
- thread's stack data_addr is in. */
-
- /* Perhaps it's on a thread's stack? */
- found = False;
- VG_(thread_stack_reset_iter)(&tid);
- while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
- if (stack_min >= stack_max)
- continue; /* ignore obviously stupid cases */
- if (stack_min - VG_STACK_REDZONE_SZB <= data_addr
- && data_addr <= stack_max) {
- found = True;
- break;
- }
- }
- if (!found) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
- return False;
- }
-
- /* We conclude data_addr is in thread tid's stack. Unwind the
- stack to get a bunch of (ip,sp,fp) triples describing the
- frames, and for each frame, consider the local variables. */
-
- n_frames = VG_(get_StackTrace)( tid, ips, N_FRAMES,
- sps, fps, 0/*first_ip_delta*/ );
- vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
- for (j = 0; j < n_frames; j++) {
- if (consider_vars_in_frame( dname1, dname2, n_dname,
- data_addr,
- ips[j], sps[j], fps[j], tid, j )) {
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
- return True;
- }
- }
-
- /* We didn't find anything useful. */
- dname1[n_dname-1] = dname2[n_dname-1] = 0;
- return False;
-# undef N_FRAMES
-}
-
-/// end Generate data description from DWARF3 debug info
-/////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////
-
/* Map a code address to the name of a shared object file or the
executable. Returns False if no idea; otherwise True. Doesn't
require debug info. Caller supplies buf and nbuf. */
@@ -1773,10 +1334,12 @@
}
-/*------------------------------------------------------------*/
-/*--- For unwinding the stack using --- */
-/*--- pre-summarised DWARF3 .eh_frame info ---*/
-/*------------------------------------------------------------*/
+/*--------------------------------------------------------------*/
+/*--- ---*/
+/*--- TOP LEVEL: FOR UNWINDING THE STACK USING ---*/
+/*--- DWARF3 .eh_frame INFO ---*/
+/*--- ---*/
+/*--------------------------------------------------------------*/
/* Gather up all the constant pieces of info needed to evaluate
a CfiExpr into one convenient struct. */
@@ -2002,6 +1565,459 @@
}
+/*--------------------------------------------------------------*/
+/*--- ---*/
+/*--- TOP LEVEL: GENERATE DESCRIPTION OF DATA ADDRESSES ---*/
+/*--- FROM DWARF3 DEBUG INFO ---*/
+/*--- ---*/
+/*--------------------------------------------------------------*/
+
+/* Evaluate the location expression/list for var, to see whether or
+ not data_addr falls within the variable. If so also return the
+ offset of data_addr from the start of the variable. Note that
+ regs, which supplies ip,sp,fp values, will be NULL for global
+ variables, and non-NULL for local variables. */
+static Bool data_address_is_in_var ( /*OUT*/UWord* offset,
+ DiVariable* var,
+ RegSummary* regs,
+ Addr data_addr )
+{
+ SizeT var_szB;
+ GXResult res;
+ Bool show = False;
+ vg_assert(var->name);
+ vg_assert(var->type);
+ vg_assert(var->gexpr);
+ var_szB = ML_(sizeOfType)(var->type);
+
+ if (show) {
+ VG_(printf)("VVVV: find loc: %s :: ", var->name );
+ ML_(pp_Type_C_ishly)( var->type );
+ VG_(printf)("\n");
+ }
+
+ res = ML_(evaluate_GX)( var->gexpr, var->fbGX, regs );
+
+ if (show) VG_(printf)("VVVV: -> 0x%lx %s\n", res.res,
+ res.failure ? res.failure : "(success)");
+ if (!res.failure && res.res <= data_addr
+ && data_addr < res.res + var_szB) {
+ *offset = data_addr - res.res;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+
+/* Format the acquired information into dname1[0 .. n_dname-1] and
+ dname2[0 .. n_dname-1] in an understandable way. Not so easy.
+ If frameNo is -1, this is assumed to be a global variable; else
+ a local variable. */
+static void format_message ( /*OUT*/Char* dname1,
+ /*OUT*/Char* dname2,
+ Int n_dname,
+ Addr data_addr,
+ DiVariable* var,
+ OffT var_offset,
+ OffT residual_offset,
+ XArray* /*UChar*/ described,
+ Int frameNo,
+ ThreadId tid )
+{
+ Bool have_descr, have_srcloc;
+ UChar* vo_plural = var_offset == 1 ? "" : "s";
+ UChar* ro_plural = residual_offset == 1 ? "" : "s";
+
+ vg_assert(frameNo >= -1);
+ vg_assert(dname1 && dname2 && n_dname > 1);
+ vg_assert(described);
+ vg_assert(var && var->name);
+ have_descr = VG_(sizeXA)(described) > 0
+ && *(UChar*)VG_(indexXA)(described,0) != '\0';
+ have_srcloc = var->fileName && var->lineNo > 0;
+
+ dname1[0] = dname2[0] = '\0';
+
+ /* ------ local cases ------ */
+
+ if ( frameNo >= 0 && (!have_srcloc) && (!have_descr) ) {
+ /* no srcloc, no description:
+ Address 0x7fefff6cf is 543 bytes inside local var "a",
+ in frame #1 of thread 1
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside local var \"%s\",",
+ data_addr, var_offset, vo_plural, var->name );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "in frame #%d of thread %d", frameNo, (Int)tid);
+ }
+ else
+ if ( frameNo >= 0 && have_srcloc && (!have_descr) ) {
+ /* no description:
+ Address 0x7fefff6cf is 543 bytes inside local var "a"
+ declared at dsyms7.c:17, in frame #1 of thread 1
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside local var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "declared at %s:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid);
+ }
+ else
+ if ( frameNo >= 0 && (!have_srcloc) && have_descr ) {
+ /* no srcloc:
+ Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2
+ in frame #1 of thread 1
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside %s%s",
+ data_addr, residual_offset, ro_plural, var->name,
+ VG_(indexXA)(described,0) );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "in frame #%d of thread %d", frameNo, (Int)tid);
+ }
+ else
+ if ( frameNo >= 0 && have_srcloc && have_descr ) {
+ /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+ declared at dsyms7.c:17, in frame #1 of thread 1 */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ VG_(indexXA)(described,0) );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "declared at %s:%d, in frame #%d of thread %d",
+ var->fileName, var->lineNo, frameNo, (Int)tid);
+ }
+ else
+ /* ------ global cases ------ */
+ if ( frameNo >= -1 && (!have_srcloc) && (!have_descr) ) {
+ /* no srcloc, no description:
+ Address 0x7fefff6cf is 543 bytes inside global var "a"
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside global var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ }
+ else
+ if ( frameNo >= -1 && have_srcloc && (!have_descr) ) {
+ /* no description:
+ Address 0x7fefff6cf is 543 bytes inside global var "a"
+ declared at dsyms7.c:17
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside global var \"%s\"",
+ data_addr, var_offset, vo_plural, var->name );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "declared at %s:%d",
+ var->fileName, var->lineNo);
+ }
+ else
+ if ( frameNo >= -1 && (!have_srcloc) && have_descr ) {
+ /* no srcloc:
+ Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+ a global variable
+ */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ VG_(indexXA)(described,0) );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "a global variable");
+ }
+ else
+ if ( frameNo >= -1 && have_srcloc && have_descr ) {
+ /* Address 0x7fefff6cf is 2 bytes inside a[3].xyzzy[21].c2,
+ a global variable declared at dsyms7.c:17 */
+ VG_(snprintf)(
+ dname1, n_dname,
+ "Address 0x%lx is %lu byte%s inside %s%s,",
+ data_addr, residual_offset, ro_plural, var->name,
+ VG_(indexXA)(described,0) );
+ VG_(snprintf)(
+ dname2, n_dname,
+ "a global variable declared at %s:%d",
+ var->fileName, var->lineNo);
+ }
+ else
+ vg_assert(0);
+
+ 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
+ False. */
+static
+Bool consider_vars_in_frame ( /*OUT*/Char* dname1,
+ /*OUT*/Char* dname2,
+ Int n_dname,
+ Addr data_addr,
+ Addr ip, Addr sp, Addr fp,
+ /* shown to user: */
+ ThreadId tid, Int frameNo )
+{
+ Word i;
+ DebugInfo* di;
+ RegSummary regs;
+
+ static UInt n_search = 0;
+ static UInt n_steps = 0;
+ n_search++;
+
+ /* 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_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 False;
+
+ if (0 && ((n_search & 0x1) == 0))
+ VG_(printf)("consider_vars_in_frame: %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 False;
+
+ /* 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 = sp;
+ regs.fp = fp;
+
+ /* "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 (!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 );
+ SizeT offset;
+ if (data_address_is_in_var( &offset, var, ®s, data_addr )) {
+ OffT residual_offset = 0;
+ XArray* described = ML_(describe_type)( &residual_offset,
+ var->type, offset );
+ format_message( dname1, dname2, n_dname,
+ data_addr, var, offset, residual_offset,
+ described, frameNo, tid );
+ VG_(deleteXA)( described );
+ return True;
+ }
+ }
+ }
+
+ return False;
+}
+
+/* Try to form some description of data_addr by looking at the DWARF3
+ debug info we have. This considers all global variables, and all
+ frames in the stacks of all threads. Result (or as much as will
+ fit) is put into into dname{1,2}[0 .. n_dname-1] and is guaranteed
+ to be zero terminated. */
+Bool VG_(get_data_description)( /*OUT*/Char* dname1,
+ /*OUT*/Char* dname2,
+ Int n_dname,
+ Addr data_addr )
+{
+# define N_FRAMES 8
+ Addr ips[N_FRAMES], sps[N_FRAMES], fps[N_FRAMES];
+ UInt n_frames;
+
+ Addr stack_min, stack_max;
+ ThreadId tid;
+ Bool found;
+ DebugInfo* di;
+ Word j;
+
+ vg_assert(n_dname > 1);
+ dname1[n_dname-1] = dname2[n_dname-1] = 0;
+
+ if (0) VG_(printf)("GDD: dataaddr %p\n", data_addr);
+
+ /* First, see if data_addr is (or is part of) a global variable.
+ Loop over the DebugInfos we have. Check data_addr against the
+ outermost scope of all of them, as that should be a global
+ scope. */
+ for (di = debugInfo_list; di != NULL; di = di->next) {
+ OSet* global_scope;
+ Int gs_size;
+ Addr zero;
+ DiAddrRange* global_arange;
+ Word i;
+ XArray* vars;
+
+ /* text segment missing? unlikely, but handle it .. */
+ if (di->text_size == 0)
+ continue;
+ /* any var info at all? */
+ if (!di->varinfo)
+ continue;
+ /* perhaps this object didn't contribute any vars at all? */
+ if (VG_(sizeXA)( di->varinfo ) == 0)
+ continue;
+ global_scope = *(OSet**)VG_(indexXA)( di->varinfo, 0 );
+ vg_assert(global_scope);
+ gs_size = VG_(OSetGen_Size)( global_scope );
+ /* The global scope might be completely empty if this
+ compilation unit declared locals but nothing global. */
+ if (gs_size == 0)
+ continue;
+ /* But if it isn't empty, then it must contain exactly one
+ element, which covers the entire address range. */
+ vg_assert(gs_size == 1);
+ /* Fish out the global scope and check it is as expected. */
+ zero = 0;
+ global_arange
+ = VG_(OSetGen_Lookup)( global_scope, &zero );
+ /* The global range from (Addr)0 to ~(Addr)0 must exist */
+ vg_assert(global_arange);
+ vg_assert(global_arange->aMin == (Addr)0
+ && global_arange->aMax == ~(Addr)0);
+ /* Any vars in this range? */
+ if (!global_arange->vars)
+ continue;
+ /* Ok, there are some vars in the global scope of this
+ DebugInfo. Wade through them and see if the data addresses
+ of any of them bracket data_addr. */
+ vars = global_arange->vars;
+ for (i = 0; i < VG_(sizeXA)( vars ); i++) {
+ SizeT offset;
+ DiVariable* var = (DiVariable*)VG_(indexXA)( vars, i );
+ vg_assert(var->name);
+ /* Note we use a NULL RegSummary* here. It can't make any
+ sense for a global variable to have a location expression
+ which depends on a SP/FP/IP value. So don't supply any.
+ This means, if the evaluation of the location
+ expression/list requires a register, we have to let it
+ fail. */
+ if (data_address_is_in_var( &offset, var,
+ NULL/* RegSummary* */,
+ data_addr )) {
+ OffT residual_offset = 0;
+ XArray* described = ML_(describe_type)( &residual_offset,
+ var->type, offset );
+ format_message( dname1, dname2, n_dname,
+ data_addr, var, offset, residual_offset,
+ described, -1/*frameNo*/, tid );
+ VG_(deleteXA)( described );
+ dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ return True;
+ }
+ }
+ }
+
+ /* Ok, well it's not a global variable. So now let's snoop around
+ in the stacks of all the threads. First try to figure out which
+ thread's stack data_addr is in. */
+
+ /* Perhaps it's on a thread's stack? */
+ found = False;
+ VG_(thread_stack_reset_iter)(&tid);
+ while ( VG_(thread_stack_next)(&tid, &stack_min, &stack_max) ) {
+ if (stack_min >= stack_max)
+ continue; /* ignore obviously stupid cases */
+ if (stack_min - VG_STACK_REDZONE_SZB <= data_addr
+ && data_addr <= stack_max) {
+ found = True;
+ break;
+ }
+ }
+ if (!found) {
+ dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ return False;
+ }
+
+ /* We conclude data_addr is in thread tid's stack. Unwind the
+ stack to get a bunch of (ip,sp,fp) triples describing the
+ frames, and for each frame, consider the local variables. */
+
+ n_frames = VG_(get_StackTrace)( tid, ips, N_FRAMES,
+ sps, fps, 0/*first_ip_delta*/ );
+ vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
+ for (j = 0; j < n_frames; j++) {
+ if (consider_vars_in_frame( dname1, dname2, n_dname,
+ data_addr,
+ ips[j], sps[j], fps[j], tid, j )) {
+ dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ return True;
+ }
+ }
+
+ /* We didn't find anything useful. */
+ dname1[n_dname-1] = dname2[n_dname-1] = 0;
+ return False;
+# undef N_FRAMES
+}
+
+
/*------------------------------------------------------------*/
/*--- DebugInfo accessor functions ---*/
/*------------------------------------------------------------*/
Modified: branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/priv_d3basics.h 2008-02-17 00:30:12 UTC (rev 7416)
@@ -587,7 +587,7 @@
/* Evaluation of a DWARF3 expression (and hence of a GExpr) may
require knowing a suitably contextualising set of values for the
- instruction, frame and stack pointer (and, in general, all
+ instruction, frame and stack pointers (and, in general, all
registers, though we punt on such generality here). Here's a
struct to carry the bare essentials. */
typedef
@@ -603,10 +603,10 @@
GXResult;
/* Evaluate a guarded expression. If regs is NULL, then gx is assumed
- (and checked) to contain just a single guarded expression, which a
+ (and checked) to contain just a single guarded expression, with a
guard which covers the entire address space and so always evaluates
to True (iow, gx is a single unconditional expression). If regs is
- non-NULL then its 'ip' value is used to select which of the
+ non-NULL then its .ip value is used to select which of the
embedded DWARF3 location expressions to use, and that is duly
evaluated.
Modified: branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/priv_storage.h 2008-02-17 00:30:12 UTC (rev 7416)
@@ -385,9 +385,16 @@
*/
XArray* /* of OSet of DiAddrRange */varinfo;
- /* For the purposes of deletion: */
- TyAdmin* tyadmins;
- GExpr* gexprs;
+ /* These are lists of the relevant typed objects, held here
+ expressly for the purposes of visiting each object exactly once
+ when we need to delete them. */
+
+ /* A list of TyAdmin structs, and the payloads that they refer
+ to. */
+ TyAdmin* admin_tyadmins;
+
+ /* A list of guarded DWARF3 expressions. */
+ GExpr* admin_gexprs;
};
/* --------------------- functions --------------------- */
Modified: branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-17 00:30:12 UTC (rev 7416)
@@ -2974,10 +2974,10 @@
/* record the TyAdmins and the GExprs in di so they can be freed
later */
- vg_assert(!di->tyadmins);
- di->tyadmins = admin;
- vg_assert(!di->gexprs);
- di->gexprs = gexprs;
+ vg_assert(!di->admin_tyadmins);
+ di->admin_tyadmins = admin;
+ vg_assert(!di->admin_gexprs);
+ di->admin_gexprs = gexprs;
}
Modified: branches/DATASYMS/coregrind/m_debuginfo/storage.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/storage.c 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/storage.c 2008-02-17 00:30:12 UTC (rev 7416)
@@ -522,67 +522,168 @@
}
-static Word cmp_for_DiAddrRange ( const void* keyV, const void* elemV ) {
+Word ML_(cmp_for_DiAddrRange_range) ( const void* keyV,
+ const void* elemV ) {
const Addr* key = (const Addr*)keyV;
const DiAddrRange* elem = (const DiAddrRange*)elemV;
if (0)
- VG_(printf)("cmp_for_DiAddrRange: %p vs %p\n", *key, elem->aMin);
+ VG_(printf)("cmp_for_DiAddrRange_range: %p vs %p\n",
+ *key, elem->aMin);
if ((*key) < elem->aMin) return -1;
- if ((*key) > elem->aMin) return 1;
- return 0;
-}
-Word ML_(cmp_for_DiAddrRange_range) ( const void* keyV, const void* elemV ) {
- const Addr* key = (const Addr*)keyV;
- const DiAddrRange* elem = (const DiAddrRange*)elemV;
- if (0)
- VG_(printf)("cmp_for_DiAddrRange_range: %p vs %p\n", *key, elem->aMin);
- if ((*key) < elem->aMin) return -1;
if ((*key) > elem->aMax) return 1;
return 0;
}
+static
+void show_scope ( OSet* /* of DiAddrRange */ scope, HChar* who )
+{
+ DiAddrRange* range;
+ VG_(printf)("Scope \"%s\" = {\n", who);
+ VG_(OSetGen_ResetIter)( scope );
+ while (True) {
+ range = VG_(OSetGen_Next)( scope );
+ if (!range) break;
+ VG_(printf)(" %p .. %p: %lu vars\n", range->aMin, range->aMax,
+ range->vars ? VG_(sizeXA)(range->vars) : 0);
+ }
+ VG_(printf)("}\n");
+}
+
/* 'inner' is an XArray of DiAddrRange. Find the entry corresponding
to [aMin,aMax]. If that doesn't exist, create one. Take care to
- preserve the invariant that none of the address ranges overlap.
- That's unlikely to be the case unless the DWARF3 from which these
- calls results contains bogus range info; however in the interests
- of robustness, do handle the case. */
-static DiAddrRange* find_or_create_arange (
- OSet* /* of DiAddrRange */ inner,
- Addr aMin,
- Addr aMax
- )
+ preserve the invariant that none of the address ranges have the
+ same starting value (aMin). That's unlikely to be the case unless
+ the DWARF3 from which these calls results contains bogus range
+ info; however in the interests of robustness, do handle the
+ case. */
+static void add_var_to_arange (
+ /*MOD*/OSet* /* of DiAddrRange */ scope,
+ Addr aMin,
+ Addr aMax,
+ DiVariable* var
+ )
{
- DiAddrRange* old = VG_(OSetGen_Lookup)( inner, &aMin );
- if (!old) {
- DiAddrRange tmp;
- tmp.aMin = aMin;
- tmp.aMax = aMax;
- tmp.vars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
- sizeof(DiVariable) );
- old = VG_(OSetGen_AllocNode)( inner, sizeof(DiAddrRange) );
- vg_assert(old);
- *old = tmp;
- VG_(OSetGen_Insert)( inner, old );
+ DiAddrRange *first, *last;
+ DiAddrRange *range, *rangep;
+ vg_assert(aMin <= aMax);
+
+ if (0) VG_(printf)("add_var_to_arange: %p .. %p\n", aMin, aMax);
+ if (0) show_scope( scope, "add_var_to_arange(1)" );
+
+ /* See if the lower end of the range (aMin) falls exactly on an
+ existing range boundary. If not, find the range it does fall
+ into, and split it (copying the variables in the process), so
+ that aMin does exactly fall on a range boundary. */
+ first = VG_(OSetGen_Lookup)( scope, &aMin );
+ /* It must be present, since the presented OSet must cover
+ the entire address range. */
+ vg_assert(first);
+ vg_assert(first->aMin <= first->aMax);
+ vg_assert(first->aMin <= aMin && aMin <= first->aMax);
+
+ if (first->aMin < aMin) {
+ DiAddrRange* nyu;
+ /* Ok. We'll have to split 'first'. */
+ /* truncate the upper end of 'first' */
+ Addr tmp = first->aMax;
+ first->aMax = aMin-1;
+ vg_assert(first->aMin <= first->aMax);
+ /* create a new range */
+ nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+ vg_assert(nyu);
+ nyu->aMin = aMin;
+ nyu->aMax = tmp;
+ vg_assert(nyu->aMin <= nyu->aMax);
+ /* copy vars into it */
+ vg_assert(first->vars);
+ nyu->vars = VG_(cloneXA)( first->vars );
+ vg_assert(nyu->vars);
+ VG_(OSetGen_Insert)( scope, nyu );
+ first = nyu;
}
- return old;
+
+ vg_assert(first->aMin == aMin);
+
+ /* Now do exactly the same for the upper end (aMax): if it doesn't
+ fall on a boundary, cause it to do so by splitting the range it
+ does currently fall into. */
+ last = VG_(OSetGen_Lookup)( scope, &aMax );
+ vg_assert(last->aMin <= last->aMax);
+ vg_assert(last->aMin <= aMax && aMax <= last->aMax);
+
+ if (aMax < last->aMax) {
+ DiAddrRange* nyu;
+ /* We have to split 'last'. */
+ /* truncate the lower end of 'last' */
+ Addr tmp = last->aMin;
+ last->aMin = aMax+1;
+ vg_assert(last->aMin <= last->aMax);
+ /* create a new range */
+ nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+ vg_assert(nyu);
+ nyu->aMin = tmp;
+ nyu->aMax = aMax;
+ vg_assert(nyu->aMin <= nyu->aMax);
+ /* copy vars into it */
+ vg_assert(last->vars);
+ nyu->vars = VG_(cloneXA)( last->vars );
+ vg_assert(nyu->vars);
+ VG_(OSetGen_Insert)( scope, nyu );
+ last = nyu;
+ }
+
+ vg_assert(aMax == last->aMax);
+
+ /* Great. Now we merely need to iterate over the segments from
+ 'first' to 'last' inclusive, and add 'var' to the variable set
+ of each of them. */
+ if (0) show_scope( scope, "add_var_to_arange(2)" );
+
+ range = rangep = NULL;
+ VG_(OSetGen_ResetIterAt)( scope, &aMin );
+ while (True) {
+ range = VG_(OSetGen_Next)( scope );
+ if (!range) break;
+ if (range->aMin >= aMax) break;
+ if (0) VG_(printf)("have range %p %p\n",
+ range->aMin, range->aMax);
+
+ /* Sanity checks */
+ if (!rangep) {
+ /* This is the first in the range */
+ vg_assert(range->aMin == aMin);
+ } else {
+ vg_assert(rangep->aMax + 1 == range->aMin);
+ }
+
+ vg_assert(range->vars);
+ VG_(addToXA)( range->vars, var );
+
+ rangep = range;
+ }
+ /* Done. We should have seen at least one range. */
+ vg_assert(rangep);
+ vg_assert(rangep->aMax == aMax);
}
+/* Top-level place to call to add a variable description (as extracted
+ from a DWARF3 .debug_info section. */
void ML_(addVar)( struct _DebugInfo* di,
Int level,
Addr aMin,
Addr aMax,
- UChar* name,
+ UChar* name, /* in di's .strchunks */
Type* type,
GExpr* gexpr,
GExpr* fbGX,
- UChar* fileName, /* where decl'd - may be NULL */
+ UChar* fileName, /* where decl'd - may be NULL.
+ in di's .strchunks */
Int lineNo, /* where decl'd - may be zero */
Bool show )
{
- OSet* /* of DiAddrRange */ inner;
- DiAddrRange* range;
- DiVariable var;
+ OSet* /* of DiAddrRange */ scope;
+ DiVariable var;
+ Bool all;
if (0) {
VG_(printf)(" ML_(addVar): level %d %p-%p %s :: ",
@@ -615,35 +716,120 @@
vg_assert(level < 256); /* arbitrary; stay sane */
/* Expand the top level array enough to map this level */
while ( VG_(sizeXA)(di->varinfo) <= level ) {
- inner = VG_(OSetGen_Create)( offsetof(DiAddrRange,aMin),
- cmp_for_DiAddrRange,
+ DiAddrRange* nyu;
+ scope = VG_(OSetGen_Create)( offsetof(DiAddrRange,aMin),
+ ML_(cmp_for_DiAddrRange_range),
ML_(dinfo_zalloc), ML_(dinfo_free) );
- if (0) VG_(printf)("create: inner = %p, adding at %ld\n",
- inner, VG_(sizeXA)(di->varinfo));
- VG_(addToXA)( di->varinfo, &inner );
+ vg_assert(scope);
+ if (0) VG_(printf)("create: scope = %p, adding at %ld\n",
+ scope, VG_(sizeXA)(di->varinfo));
+ VG_(addToXA)( di->varinfo, &scope );
+ /* Add a single range covering the entire address space. At
+ level 0 we require this doesn't get split. At levels above 0
+ we require that any additions to it cause it to get split. */
+ nyu = VG_(OSetGen_AllocNode)( scope, sizeof(DiAddrRange) );
+ vg_assert(nyu);
+ nyu->aMin = (Addr)0;
+ nyu->aMax = ~(Addr)0;
+ nyu->vars = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free),
+ sizeof(DiVariable) );
+ vg_assert(nyu->vars);
+ VG_(OSetGen_Insert)( scope, nyu );
}
vg_assert( VG_(sizeXA)(di->varinfo) > level );
- inner = *(OSet**)VG_(indexXA)( di->varinfo, level );
- vg_assert(inner);
+ scope = *(OSet**)VG_(indexXA)( di->varinfo, level );
+ vg_assert(scope);
- /* Now we need to find the relevant DiAddrRange within 'inner',
- or create one if not present. */
- /* DiAddrRange* */ range = find_or_create_arange( inner, aMin, aMax );
- /* DiVariable var; */
var.name = name;
var.type = type;
var.gexpr = gexpr;
var.fbGX = fbGX;
var.fileName = fileName;
var.lineNo = lineNo;
- vg_assert(range);
- vg_assert(range->vars);
- vg_assert(range->aMin == aMin);
- VG_(addToXA)( range->vars, &var );
+
+ all = aMin == (Addr)0 && aMax == ~(Addr)0;
+ vg_assert(level == 0 ? all : !all);
+
+ add_var_to_arange( /*MOD*/scope, aMin, aMax, &var );
}
+/* This really just checks the constructed data structure, as there is
+ no canonicalisation to do. */
+static void canonicaliseVarInfo ( struct _DebugInfo* di )
+{
+ Word i, nInThisScope;
+
+ if (!di->varinfo)
+ return;
+
+ for (i = 0; i < VG_(sizeXA)(di->varinfo); i++) {
+
+ DiAddrRange *range, *rangep;
+ OSet* scope = *(OSet**)VG_(indexXA)(di->varinfo, i);
+ if (!scope) continue;
+
+ /* Deal with the global-scope case. */
+ if (i == 0) {
+ Addr zero = 0;
+ vg_assert(VG_(OSetGen_Size)( scope ) == 1);
+ range = VG_(OSetGen_Lookup)( scope, &zero );
+ vg_assert(range);
+ vg_assert(range->aMin == (Addr)0);
+ vg_assert(range->aMax == ~(Addr)0);
+ continue;
+ }
+
+ /* All the rest of this is for the local-scope case. */
+ /* iterate over all entries in 'scope' */
+ nInThisScope = 0;
+ range = rangep = NULL;
+ VG_(OSetGen_ResetIter)(scope);
+ while (True) {
+ range = VG_(OSetGen_Next)(scope);
+ if (!range) {
+ /* We just saw the last one. There must have been at
+ least one entry in the range. */
+ vg_assert(rangep);
+ vg_assert(rangep->aMax == ~(Addr)0);
+ break;
+ }
+
+ vg_assert(range->aMin <= range->aMax);
+ vg_assert(range->vars);
+
+ if (!rangep) {
+ /* This is the first entry in the range. */
+ vg_assert(range->aMin == 0);
+ } else {
+ vg_assert(rangep->aMax + 1 == range->aMin);
+ }
+
+ rangep = range;
+ nInThisScope++;
+ } /* iterating over ranges in a given scope */
+
+ /* If there's only one entry in this (local) scope, it must
+ cover the entire address space (obviously), but it must not
+ contain any vars. */
+
+ vg_assert(nInThisScope > 0);
+ if (nInThisScope == 1) {
+ Addr zero = 0;
+ vg_assert(VG_(OSetGen_Size)( scope ) == 1);
+ range = VG_(OSetGen_Lookup)( scope, &zero );
+ vg_assert(range);
+ vg_assert(range->aMin == (Addr)0);
+ vg_assert(range->aMax == ~(Addr)0);
+ vg_assert(range->vars);
+ vg_assert(VG_(sizeXA)(range->vars) == 0);
+ }
+
+ } /* iterate over scopes */
+}
+
+
/*------------------------------------------------------------*/
/*--- Canonicalisers ---*/
/*------------------------------------------------------------*/
@@ -1060,13 +1246,14 @@
}
-/* Canonicalise the tables held by 'si', in preparation for use. Call
+/* Canonicalise the tables held by 'di', in preparation for use. Call
this after finishing adding entries to these tables. */
void ML_(canonicaliseTables) ( struct _DebugInfo* di )
{
canonicaliseSymtab ( di );
canonicaliseLoctab ( di );
canonicaliseCFI ( di );
+ canonicaliseVarInfo ( di );
}
Modified: branches/DATASYMS/coregrind/m_debuginfo/tytypes.c
===================================================================
--- branches/DATASYMS/coregrind/m_debuginfo/tytypes.c 2008-02-17 00:25:49 UTC (rev 7415)
+++ branches/DATASYMS/coregrind/m_debuginfo/tytypes.c 2008-02-17 00:30:12 UTC (rev 7416)
@@ -80,24 +80,23 @@
return type;
}
-void ML_(delete_TyAtom)( TyAtom* atom ) {
+static void delete_TyAtom ( TyAtom* atom ) {
/* .name is in DebugInfo.strchunks */
ML_(dinfo_free)(atom);
}
-void ML_(delete_TyField)( TyField* field ) {
+static void delete_TyField ( TyField* field ) {
/* .name is in DebugInfo.strchunks */
/* typeR and loc will be on the admin list; no need to free */
ML_(dinfo_free)(field);
}
-void ML_(delete_TyBounds)( TyBounds* bounds ) {
+static void delete_TyBounds ( TyBounds* bounds ) {
ML_(dinfo_free)(bounds);
}
-void ML_(delete_D3Expr)( D3Expr* expr ) {
+static void delete_D3Expr ( D3Expr* expr ) {
/* .bytes is in DebugInfo.strchunks */
ML_(dinfo_free)(expr);
}
-__attribute__((noinline))
-void ML_(delete_Type)( Type* ty ) {
+static void delete_Type ( Type* ty ) {
switch (ty->tag) {
case Ty_Base:
/* .name is in DebugInfo.strchunks */
@@ -144,11 +143,11 @@
void ML_(delete_TyAdmin_and_payload) ( TyAdmin* ad ) {
vg_assert(ad->payload);
switch (ad->tag) {
- case TyA_Type: ML_(delete_Type)(ad->payload); break;
- case TyA_Atom: ML_(delete_TyAtom)(ad->payload); break;
- case TyA_Expr: ML_(delete_D3Expr)(ad->payload); break;
- case TyA_Field: ML_(delete_TyField)(ad->payload); break;
- case TyA_Bounds: ML_(delete_TyBounds)(ad->payload); break;
+ case TyA_Type: delete_Type(ad->payload); break;
+ case TyA_Atom: delete_TyAtom(ad->payload); break;
+ case TyA_Expr: delete_D3Expr(ad->payload); break;
+ case TyA_Field: delete_TyField(ad->payload); break;
+ case TyA_Bounds: delete_TyBounds(ad->payload); break;
default: vg_assert(0);
}
ML_(dinfo_free)(ad);
|
|
From: <sv...@va...> - 2008-02-17 00:25:50
|
Author: sewardj
Date: 2008-02-17 00:25:49 +0000 (Sun, 17 Feb 2008)
New Revision: 7415
Log:
Add a new method, VG_(cloneXA), which clones an existing XArray.
Modified:
branches/DATASYMS/coregrind/m_xarray.c
branches/DATASYMS/include/pub_tool_xarray.h
Modified: branches/DATASYMS/coregrind/m_xarray.c
===================================================================
--- branches/DATASYMS/coregrind/m_xarray.c 2008-02-17 00:24:22 UTC (rev 7414)
+++ branches/DATASYMS/coregrind/m_xarray.c 2008-02-17 00:25:49 UTC (rev 7415)
@@ -76,6 +76,32 @@
return xa;
}
+XArray* VG_(cloneXA)( XArray* xao )
+{
+ struct _XArray* xa = (struct _XArray*)xao;
+ struct _XArray* nyu;
+ vg_assert(xa);
+ vg_assert(xa->alloc);
+ vg_assert(xa->free);
+ vg_assert(xa->elemSzB >= 1);
+ nyu = xa->alloc( sizeof(struct _XArray) );
+ if (!nyu)
+ return NULL;
+ /* Copy everything verbatim ... */
+ *nyu = *xa;
+ /* ... except we have to clone the contents-array */
+ if (nyu->arr) {
+ nyu->arr = nyu->alloc( nyu->totsizeE * nyu->elemSzB );
+ if (!nyu->arr) {
+ nyu->free(nyu);
+ return NULL;
+ }
+ VG_(memcpy)( nyu->arr, xa->arr, nyu->totsizeE * nyu->elemSzB );
+ }
+ /* We're done! */
+ return nyu;
+}
+
void VG_(deleteXA) ( XArray* xao )
{
struct _XArray* xa = (struct _XArray*)xao;
Modified: branches/DATASYMS/include/pub_tool_xarray.h
===================================================================
--- branches/DATASYMS/include/pub_tool_xarray.h 2008-02-17 00:24:22 UTC (rev 7414)
+++ branches/DATASYMS/include/pub_tool_xarray.h 2008-02-17 00:25:49 UTC (rev 7415)
@@ -99,6 +99,11 @@
than n elements in the array. */
extern void VG_(dropTailXA) ( XArray*, Word );
+/* Make a new, completely independent copy of the given XArray, using
+ the existing allocation function to allocate the new space.
+ Returns NULL if the allocation function didn't manage to allocate
+ space (but did return NULL rather than merely abort.) */
+extern XArray* VG_(cloneXA)( XArray* xa );
#endif // __PUB_TOOL_XARRAY_H
|
|
From: <sv...@va...> - 2008-02-17 00:24:25
|
Author: sewardj
Date: 2008-02-17 00:24:22 +0000 (Sun, 17 Feb 2008)
New Revision: 7414
Log:
* change the default ordering unboxed order from signed word (Word)
to unsigned word (UWord)
* change some size-of-the-OSet measures from Int to Word
* add a method VG_(OSetGen_ResetIterAt) to start the iterator
at a given point, analogous to hg_wordset.c:HG_(initIterAtFM)
(Konstantin Serebryany)
Modified:
branches/DATASYMS/coregrind/m_oset.c
branches/DATASYMS/include/pub_tool_oset.h
Modified: branches/DATASYMS/coregrind/m_oset.c
===================================================================
--- branches/DATASYMS/coregrind/m_oset.c 2008-02-16 02:37:03 UTC (rev 7413)
+++ branches/DATASYMS/coregrind/m_oset.c 2008-02-17 00:24:22 UTC (rev 7414)
@@ -113,7 +113,7 @@
OSetCmp_t cmp; // compare a key and an element, or NULL
OSetAlloc_t alloc; // allocator
OSetFree_t free; // deallocator
- Int nElems; // number of elements in the tree
+ Word nElems; // number of elements in the tree
AvlNode* root; // root node
AvlNode* nodeStack[STACK_MAX]; // Iterator node stack
@@ -175,8 +175,8 @@
// Compare the first word of each element. Inlining is *crucial*.
static inline Word fast_cmp(void* k, AvlNode* n)
{
- Word w1 = *(Word*)k;
- Word w2 = *(Word*)elem_of_node(n);
+ UWord w1 = *(UWord*)k;
+ UWord w2 = *(UWord*)elem_of_node(n);
// In previous versions, we tried to do this faster by doing
// "return w1 - w2". But it didn't work reliably, because the
// complete result of subtracting two N-bit numbers is an N+1-bit
@@ -189,7 +189,8 @@
}
// Compare a key and an element. Inlining is *crucial*.
-static inline Word slow_cmp(const AvlTree* t, const void* k, const AvlNode* n)
+static
+inline Word slow_cmp(const AvlTree* t, const void* k, const AvlNode* n)
{
return t->cmp(k, elem_of_node(n));
}
@@ -314,7 +315,8 @@
void VG_(OSetGen_Destroy)(AvlTree* t)
{
AvlNode* n = NULL;
- Int i = 0, sz = 0;
+ Int i = 0;
+ Word sz = 0;
vg_assert(t);
stackClear(t);
@@ -460,8 +462,9 @@
vg_assert(t);
- // Initialise. Even though OSetGen_AllocNode zeroes these fields, we should
- // do it again in case a node is removed and then re-added to the tree.
+ // Initialise. Even though OSetGen_AllocNode zeroes these fields,
+ // we should do it again in case a node is removed and then
+ // re-added to the tree.
n = node_of_elem(e);
n->left = 0;
n->right = 0;
@@ -478,9 +481,9 @@
t->stackTop = 0; // So the iterator can't get out of sync
}
-void VG_(OSetWord_Insert)(AvlTree* t, Word val)
+void VG_(OSetWord_Insert)(AvlTree* t, UWord val)
{
- Word* node = VG_(OSetGen_AllocNode)(t, sizeof(Word));
+ Word* node = VG_(OSetGen_AllocNode)(t, sizeof(UWord));
*node = val;
VG_(OSetGen_Insert)(t, node);
}
@@ -509,11 +512,11 @@
// elem_of_node because it saves about 10% on lookup time. This
// shouldn't be very dangerous because each node will have been
// checked on insertion.
- Word w1 = *(Word*)k;
- Word w2;
+ UWord w1 = *(UWord*)k;
+ UWord w2;
while (True) {
if (curr == NULL) return NULL;
- w2 = *(Word*)elem_of_node_no_check(curr);
+ w2 = *(UWord*)elem_of_node_no_check(curr);
if (w1 < w2) curr = curr->left;
else if (w1 > w2) curr = curr->right;
else return curr;
@@ -551,7 +554,7 @@
return (NULL != VG_(OSetGen_Lookup)(t, k));
}
-Bool VG_(OSetWord_Contains)(AvlTree* t, Word val)
+Bool VG_(OSetWord_Contains)(AvlTree* t, UWord val)
{
return (NULL != VG_(OSetGen_Lookup)(t, &val));
}
@@ -683,7 +686,8 @@
return False;
}
-// Remove and return the element matching the key 'k', or NULL if not present.
+// Remove and return the element matching the key 'k', or NULL
+// if not present.
void* VG_(OSetGen_Remove)(AvlTree* t, void* k)
{
// Have to find the node first, then remove it.
@@ -698,7 +702,7 @@
}
}
-Bool VG_(OSetWord_Remove)(AvlTree* t, Word val)
+Bool VG_(OSetWord_Remove)(AvlTree* t, UWord val)
{
void* n = VG_(OSetGen_Remove)(t, &val);
if (n) {
@@ -760,9 +764,9 @@
return NULL;
}
-Bool VG_(OSetWord_Next)(AvlTree* t, Word* val)
+Bool VG_(OSetWord_Next)(AvlTree* t, UWord* val)
{
- Word* n = VG_(OSetGen_Next)(t);
+ UWord* n = VG_(OSetGen_Next)(t);
if (n) {
*val = *n;
return True;
@@ -771,17 +775,81 @@
}
}
+// set up 'oset' for iteration so that the first key subsequently
+// produced VG_(OSetGen_Next) is the smallest key in the map
+// >= start_at. Naturally ">=" is defined by the comparison
+// function supplied to VG_(OSetGen_Create).
+void VG_(OSetGen_ResetIterAt)(AvlTree* oset, void* k)
+{
+ Int i;
+ AvlNode *n, *t;
+ Word cmpresS; /* signed */
+ UWord cmpresU; /* unsigned */
+
+ tl_assert(oset);
+ stackClear(oset);
+
+ if (!oset->root)
+ return;
+
+ n = NULL;
+ // We need to do regular search and fill in the stack.
+ t = oset->root;
+
+ while (True) {
+ if (t == NULL) return;
+
+ if (oset->cmp) {
+ cmpresS = (Word)slow_cmp(oset, k, t);
+ } else {
+ /* this is believed to be correct, but really needs testing
+ before the assertion is removed. */
+ vg_assert(0);
+ cmpresS = fast_cmp(k, t);
+ }
+
+ /* Switch the sense of the comparison, since the comparison
+ order of args (k vs t) above is opposite to that of the
+ corresponding code in hg_wordfm.c. */
+ if (cmpresS < 0) { cmpresS = 1; }
+ else if (cmpresS > 0) { cmpresS = -1; }
+
+ if (cmpresS == 0) {
+ // We found the exact key -- we are done.
+ // The iteration should start with this node.
+ stackPush(oset, t, 2);
+ // The stack now looks like {2, 2, ... ,2, 2}
+ return;
+ }
+ cmpresU = (UWord)cmpresS;
+ cmpresU >>=/*unsigned*/ (8 * sizeof(cmpresU) - 1);
+ vg_assert(cmpresU == 0 || cmpresU == 1);
+ if (!cmpresU) {
+ // Push this node only if we go to the left child.
+ stackPush(oset, t, 2);
+ }
+ t = cmpresU==0 ? t->left : t->right;
+ }
+ if (stackPop(oset, &n, &i)) {
+ // If we've pushed something to stack and did not find the exact key,
+ // we must fix the top element of stack.
+ tl_assert(i == 2);
+ stackPush(oset, n, 3);
+ // the stack looks like {2, 2, ..., 2, 3}
+ }
+}
+
/*--------------------------------------------------------------------*/
/*--- Miscellaneous operations ---*/
/*--------------------------------------------------------------------*/
-Int VG_(OSetGen_Size)(const AvlTree* t)
+Word VG_(OSetGen_Size)(const AvlTree* t)
{
vg_assert(t);
return t->nElems;
}
-Int VG_(OSetWord_Size)(AvlTree* t)
+Word VG_(OSetWord_Size)(AvlTree* t)
{
return VG_(OSetGen_Size)(t);
}
Modified: branches/DATASYMS/include/pub_tool_oset.h
===================================================================
--- branches/DATASYMS/include/pub_tool_oset.h 2008-02-16 02:37:03 UTC (rev 7413)
+++ branches/DATASYMS/include/pub_tool_oset.h 2008-02-17 00:24:22 UTC (rev 7414)
@@ -39,9 +39,9 @@
// It has two interfaces.
//
// - The "OSetWord_" interface provides an easier-to-use interface for the
-// case where you just want to store Word-sized values. The user provides
-// the allocation and deallocation functions, and possibly a comparison
-// function.
+// case where you just want to store UWord-sized values. The user
+// provides the allocation and deallocation functions, and possibly a
+// comparison function.
//
// - The "OSetGen_" interface provides a totally generic interface, which
// allows any kind of structure to be put into the set. The user provides
@@ -81,7 +81,7 @@
typedef void (*OSetFree_t) ( void* p );
/*--------------------------------------------------------------------*/
-/*--- Creating and destroying OSets (Word) ---*/
+/*--- Creating and destroying OSets (UWord) ---*/
/*--------------------------------------------------------------------*/
// * Create: allocates and initialises the OSet. Arguments:
@@ -102,7 +102,7 @@
extern void VG_(OSetWord_Destroy) ( OSet* os );
/*--------------------------------------------------------------------*/
-/*--- Operations on OSets (Word) ---*/
+/*--- Operations on OSets (UWord) ---*/
/*--------------------------------------------------------------------*/
// In everything that follows, the parameter 'key' is always the *address*
@@ -124,8 +124,8 @@
//
// * Next: Copies the next value according to the OSet's iterator into &val,
// advances the iterator by one, and returns True; the elements are
-// visited in order. Or, returns False if the iterator has reached the
-// set's end.
+// visited in increasing order of unsigned words (UWord). Or, returns
+// False if the iterator has reached the set's end.
//
// You can thus iterate in order through a set like this:
//
@@ -141,12 +141,12 @@
// they will return False if VG_(OSetWord_Next)() is called without an
// intervening call to VG_(OSetWord_ResetIter)().
-extern Int VG_(OSetWord_Size) ( OSet* os );
-extern void VG_(OSetWord_Insert) ( OSet* os, Word val );
-extern Bool VG_(OSetWord_Contains) ( OSet* os, Word val );
-extern Bool VG_(OSetWord_Remove) ( OSet* os, Word val );
+extern Word VG_(OSetWord_Size) ( OSet* os );
+extern void VG_(OSetWord_Insert) ( OSet* os, UWord val );
+extern Bool VG_(OSetWord_Contains) ( OSet* os, UWord val );
+extern Bool VG_(OSetWord_Remove) ( OSet* os, UWord val );
extern void VG_(OSetWord_ResetIter) ( OSet* os );
-extern Bool VG_(OSetWord_Next) ( OSet* os, Word* val );
+extern Bool VG_(OSetWord_Next) ( OSet* os, /*OUT*/UWord* val );
/*--------------------------------------------------------------------*/
@@ -234,15 +234,22 @@
// they will return NULL if VG_(OSetGen_Next)() is called without an
// intervening call to VG_(OSetGen_ResetIter)().
-extern Int VG_(OSetGen_Size) ( const OSet* os );
+extern Word VG_(OSetGen_Size) ( const OSet* os );
extern void VG_(OSetGen_Insert) ( OSet* os, void* elem );
extern Bool VG_(OSetGen_Contains) ( const OSet* os, const void* key );
extern void* VG_(OSetGen_Lookup) ( const OSet* os, const void* key );
-extern void* VG_(OSetGen_LookupWithCmp)( OSet* os, const void* key, OSetCmp_t cmp );
+extern void* VG_(OSetGen_LookupWithCmp)( OSet* os,
+ const void* key, OSetCmp_t cmp );
extern void* VG_(OSetGen_Remove) ( OSet* os, void* key );
extern void VG_(OSetGen_ResetIter) ( OSet* os );
extern void* VG_(OSetGen_Next) ( OSet* os );
+// set up 'oset' for iteration so that the first key subsequently
+// produced VG_(OSetGen_Next) is the smallest key in the map
+// >= start_at. Naturally ">=" is defined by the comparison
+// function supplied to VG_(OSetGen_Create).
+extern void VG_(OSetGen_ResetIterAt) ( OSet* oset, void* key );
+
#endif // __PUB_TOOL_OSET_H
/*--------------------------------------------------------------------*/
|