|
From: <sv...@va...> - 2007-01-17 04:36:06
|
Author: njn
Date: 2007-01-17 04:35:59 +0000 (Wed, 17 Jan 2007)
New Revision: 6529
Log:
Rewrote SP update pass. It no longer uses a zillion goto statements and
that god-awful macro, but instead uses a switch statements and some
functions. Much better and less error prone.
Modified:
branches/ORIGIN_TRACKING/coregrind/m_translate.c
branches/ORIGIN_TRACKING/memcheck/mc_main.c
branches/ORIGIN_TRACKING/memcheck/mc_translate.c
Modified: branches/ORIGIN_TRACKING/coregrind/m_translate.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/ORIGIN_TRACKING/coregrind/m_translate.c 2007-01-16 22:04:50 =
UTC (rev 6528)
+++ branches/ORIGIN_TRACKING/coregrind/m_translate.c 2007-01-17 04:35:59 =
UTC (rev 6529)
@@ -61,29 +61,37 @@
/*--- Stats ---*/
/*------------------------------------------------------------*/
=20
-static UInt n_SP_updates_fast =3D 0;
-static UInt n_SP_updates_generic_known =3D 0;
-static UInt n_SP_updates_generic_unknown =3D 0;
+static UInt n_SP_delta_known_and_handled =3D 0;
+static UInt n_SP_delta_known_but_unhandled_by_core =3D 0;
+static UInt n_SP_delta_known_but_unhandled_by_tool =3D 0;
+static UInt n_SP_delta_unknown =3D 0;
=20
void VG_(print_translation_stats) ( void )
{
Char buf[6];
- UInt n_SP_updates =3D n_SP_updates_fast + n_SP_updates_generic_known
- + n_SP_updates_generic_unknown;
- VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
+ UInt n_tot =3D
+ n_SP_delta_known_and_handled + n_SP_delta_known_but_unhandled_by_c=
ore +
+ n_SP_delta_known_but_unhandled_by_tool + n_SP_delta_unknown;
+
+ VG_(percentify)(n_SP_delta_known_and_handled, n_tot, 1, 6, buf);
VG_(message)(Vg_DebugMsg,
- "translate: fast SP updates identified: %,u (%s)",
- n_SP_updates_fast, buf );
+ " SP instr: delta known and handled: %,7u (%s)",
+ n_SP_delta_known_and_handled, buf );
=20
- VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
+ VG_(percentify)(n_SP_delta_known_but_unhandled_by_tool, n_tot, 1, 6, =
buf);
VG_(message)(Vg_DebugMsg,
- "translate: generic_known SP updates identified: %,u (%s)",
- n_SP_updates_generic_known, buf );
+ " SP instr: delta known but unhandled by tool: %,7u (%s)",
+ n_SP_delta_known_but_unhandled_by_tool, buf );
=20
- VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf=
);
+ VG_(percentify)(n_SP_delta_known_but_unhandled_by_core, n_tot, 1, 6, =
buf);
VG_(message)(Vg_DebugMsg,
- "translate: generic_unknown SP updates identified: %,u (%s)",
- n_SP_updates_generic_unknown, buf );
+ " SP instr: delta known but unhandled by core: %,7u (%s)",
+ n_SP_delta_known_but_unhandled_by_core, buf );
+
+ VG_(percentify)(n_SP_delta_unknown, n_tot, 1, 6, buf);
+ VG_(message)(Vg_DebugMsg,
+ " SP instr: delta unknown: %,7u (%s)",
+ n_SP_delta_unknown, buf );
}
=20
/*------------------------------------------------------------*/
@@ -192,6 +200,75 @@
}
=20
=20
+// Nb: if all is well, this generic case will typically be called someth=
ing
+// like < 10% of all (static) SP updates. If it's more than that, the a=
bove
+// code may be missing some cases.
+static void
+add_call_to_generic_SP_update(IRSB* bb, IRStmt* st, IRType typeof_SP,
+ Int sizeof_SP, Int offset_SP, Bool delta_k=
nown)
+{
+ IRTemp old_SP;
+ IRDirty *dcall;
+
+ /* Pass both the old and new SP values to this helper. */
+ old_SP =3D newIRTemp(bb->tyenv, typeof_SP);
+ addStmtToIRSB( bb,
+ IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP)=
)=20
+ );
+
+ // Update SP first, then call the helper. This ensures that, in the
+ // new_mem_stack_* case, that the memory allocated is really allocate=
d
+ // before the helper is called, and thus the helper is able to access
+ // it if wants.
+ dcall =3D unsafeIRDirty_0_N(=20
+ 2/*regparms*/,=20
+ "VG_(unknown_SP_update)",=20
+ VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
+ mkIRExprVec_2( IRExpr_RdTmp(old_SP),
+ st->Ist.Put.data )=20
+ );
+ addStmtToIRSB( bb, st );
+ addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
+
+ clear_SP_aliases();
+ add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
+
+ if (delta_known) {
+ n_SP_delta_known_but_unhandled_by_core++;
+ } else {
+ n_SP_delta_unknown++;
+ }
+}
+
+static void
+maybe_add_call_to_specialised_SP_update(=20
+ IRSB* bb, IRStmt* st, Char* tdict_fn_string,
+ VG_REGPARM(1) void(*tdict_fn)(Addr), IRTemp tmp, Int delta)
+{
+ if (tdict_fn) {
+
+ IRDirty *dcall =3D unsafeIRDirty_0_N(
+ 1/*regparms*/,
+ tdict_fn_string,
+ VG_(fnptr_to_fnentry)( tdict_fn ),
+ mkIRExprVec_1(IRExpr_RdTmp(tmp))
+ );
+
+ // Update SP first, then call the helper. See comment in
+ // add_call_to_generic_SP_update() for why.
+ addStmtToIRSB( bb, st );
+ addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
+
+ update_SP_aliases(-delta);
+
+ n_SP_delta_known_and_handled++;
+
+ } else {
+ n_SP_delta_known_but_unhandled_by_tool++;
+ } =20
+}
+
+
/* For tools that want to know about SP changes, this pass adds
in the appropriate hooks. We have to do it after the tool's
instrumentation, so the tool doesn't have to worry about the C calls
@@ -216,9 +293,7 @@
IRType hWordTy )
{
Int i, j, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
- IRDirty *dcall, *d;
IRStmt* st;
- IRExpr* e;
IRRegArray* descr;
IRType typeof_SP;
Long delta, con;
@@ -245,178 +320,137 @@
(sizeof_SP=3D=3D4 ? (Long)(Int)(con->Ico.U32) =
\
: (Long)(con->Ico.U64))
=20
-// XXX: convert this to a function
-# define DO(kind, syze, tmpp) =
\
- do { =
\
- if (!VG_(tdict).track_##kind##_mem_stack_##syze) =
\
- goto generic; =
\
- =
\
- /* I don't know if it's really necessary to say that the */ =
\
- /* call reads the stack pointer. But anyway, we do. */ =
\
- dcall =3D unsafeIRDirty_0_N( =
\
- 1/*regparms*/, =
\
- "track_" #kind "_mem_stack_" #syze, =
\
- VG_(fnptr_to_fnentry)( =
\
- VG_(tdict).track_##kind##_mem_stack_##syze ), =
\
- mkIRExprVec_1(IRExpr_RdTmp(tmpp)) =
\
- ); =
\
- dcall->nFxState =3D 1; =
\
- dcall->fxState[0].fx =3D Ifx_Read; =
\
- dcall->fxState[0].offset =3D layout->offset_SP; =
\
- dcall->fxState[0].size =3D layout->sizeof_SP; =
\
- =
\
- addStmtToIRSB( bb, st ); =
\
- =
\
- addStmtToIRSB( bb, IRStmt_Dirty(dcall) ); =
\
- =
\
- update_SP_aliases(-delta); =
\
- =
\
- n_SP_updates_fast++; =
\
- =
\
- } while (0)
-
clear_SP_aliases();
=20
for (i =3D 0; i < sb_in->stmts_used; i++) {
=20
st =3D sb_in->stmts[i];
=20
- /* t =3D Get(sp): curr =3D t, delta =3D 0 */
- if (st->tag !=3D Ist_WrTmp) goto case2;
- e =3D st->Ist.WrTmp.data;
- if (e->tag !=3D Iex_Get) goto case2;
- if (e->Iex.Get.offset !=3D offset_SP) goto case2;
- if (e->Iex.Get.ty !=3D typeof_SP) goto case2;
- add_SP_alias(st->Ist.WrTmp.tmp, 0);
- addStmtToIRSB( bb, st );
- continue;
+ switch (st->tag) {
=20
- case2:
- /* t' =3D curr +/- const: curr =3D t', delta +=3D/-=3D const */
- if (st->tag !=3D Ist_WrTmp) goto case3;
- e =3D st->Ist.WrTmp.data;
- if (e->tag !=3D Iex_Binop) goto case3;
- if (e->Iex.Binop.arg1->tag !=3D Iex_RdTmp) goto case3;
- if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto =
case3;
- if (e->Iex.Binop.arg2->tag !=3D Iex_Const) goto case3;
- if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
- con =3D GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
- if (IS_ADD(e->Iex.Binop.op)) {
- add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
- } else {
- add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
- }
- addStmtToIRSB( bb, st );
- continue;
-
- case3:
- /* t' =3D curr: curr =3D t' */
- if (st->tag !=3D Ist_WrTmp) goto case4;
- e =3D st->Ist.WrTmp.data;
- if (e->tag !=3D Iex_RdTmp) goto case4;
- if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4;
- add_SP_alias(st->Ist.WrTmp.tmp, delta);
- addStmtToIRSB( bb, st );
- continue;
-
- case4:
- /* Put(sp) =3D curr */
- if (st->tag !=3D Ist_Put) goto case5;
- if (st->Ist.Put.offset !=3D offset_SP) goto case5;
- if (st->Ist.Put.data->tag !=3D Iex_RdTmp) goto case5;
- if (get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) {
- IRTemp tttmp =3D st->Ist.Put.data->Iex.RdTmp.tmp;
- switch (delta) {
- case 0: continue;
- case 4: DO(die, 4, tttmp); continue;
- case -4: DO(new, 4, tttmp); continue;
- case 8: DO(die, 8, tttmp); continue;
- case -8: DO(new, 8, tttmp); continue;
- case 12: DO(die, 12, tttmp); continue;
- case -12: DO(new, 12, tttmp); continue;
- case 16: DO(die, 16, tttmp); continue;
- case -16: DO(new, 16, tttmp); continue;
- case 32: DO(die, 32, tttmp); continue;
- case -32: DO(new, 32, tttmp); continue;
- case 112: DO(die, 112, tttmp); continue;
- case -112: DO(new, 112, tttmp); continue;
- case 128: DO(die, 128, tttmp); continue;
- case -128: DO(new, 128, tttmp); continue;
- case 144: DO(die, 144, tttmp); continue;
- case -144: DO(new, 144, tttmp); continue;
- case 160: DO(die, 160, tttmp); continue;
- case -160: DO(new, 160, tttmp); continue;
- default: =20
- /* common values for ppc64: 144 128 160 112 176 */
- n_SP_updates_generic_known++;
- goto generic;
+ case Ist_WrTmp: {
+ IRExpr* data =3D st->Ist.WrTmp.data;
+ if (data->tag =3D=3D Iex_Get &&
+ data->Iex.Get.offset =3D=3D offset_SP &&
+ data->Iex.Get.ty =3D=3D typeof_SP)
+ {
+ /* t =3D Get(sp): curr =3D t, delta =3D 0 */
+ add_SP_alias(st->Ist.WrTmp.tmp, 0);
+ }
+ else if (data->tag =3D=3D Iex_Binop &&
+ data->Iex.Binop.arg1->tag =3D=3D Iex_RdTmp &&
+ data->Iex.Binop.arg2->tag =3D=3D Iex_Const &&
+ get_SP_delta(data->Iex.Binop.arg1->Iex.RdTmp.tmp,&d=
elta) &&
+ IS_ADD_OR_SUB(data->Iex.Binop.op))
+ {
+ /* t =3D curr +/- const: curr =3D t, delta +=3D/-=3D c=
onst */
+ con =3D GET_CONST(data->Iex.Binop.arg2->Iex.Const.con);
+ if (IS_ADD(data->Iex.Binop.op)) {
+ add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
+ } else {
+ add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
+ }
+ }
+ else if (data->tag =3D=3D Iex_RdTmp &&
+ get_SP_delta(data->Iex.RdTmp.tmp, &delta))
+ {
+ /* t =3D curr: curr =3D t */
+ add_SP_alias(st->Ist.WrTmp.tmp, delta);
+ }
+ addStmtToIRSB( bb, st );
+ break;
}
- } else {
- IRTemp old_SP;
- n_SP_updates_generic_unknown++;
=20
- // Nb: if all is well, this generic case will typically be
- // called something like every 1000th SP update. If it's more =
than
- // that, the above code may be missing some cases.
- generic:
- /* Pass both the old and new SP values to this helper. */
- old_SP =3D newIRTemp(bb->tyenv, typeof_SP);
- addStmtToIRSB(=20
- bb,
- IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )=20
- );
+ #define DO(kind, size, tmp) \
+ maybe_add_call_to_specialised_SP_update( \
+ bb, st, "VG_(tdict)." #kind "_mem_stack_" #size, \
+ VG_(tdict).track_##kind##_mem_stack_##size, t, delta);
+ case Ist_Put:
+ if (st->Ist.Put.offset =3D=3D offset_SP &&
+ st->Ist.Put.data->tag =3D=3D Iex_RdTmp)
+ {
+ if (get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta=
)) {
+ /* Put(sp) =3D curr */
+ IRTemp t =3D st->Ist.Put.data->Iex.RdTmp.tmp;
+ switch (delta) {
+ /* common values for ppc64: 144 128 160 112 176 */
+ case 0: break;
+ case 4: DO(die, 4, t); break;
+ case -4: DO(new, 4, t); break;
+ case 8: DO(die, 8, t); break;
+ case -8: DO(new, 8, t); break;
+ case 12: DO(die, 12, t); break;
+ case -12: DO(new, 12, t); break;
+ case 16: DO(die, 16, t); break;
+ case -16: DO(new, 16, t); break;
+ case 32: DO(die, 32, t); break;
+ case -32: DO(new, 32, t); break;
+// XXX: omitting the rare cases here.
+// case 112: DO(die, 112, t); break;
+// case -112: DO(new, 112, t); break;
+// case 128: DO(die, 128, t); break;
+// case -128: DO(new, 128, t); break;
+// case 144: DO(die, 144, t); break;
+// case -144: DO(new, 144, t); break;
+// case 160: DO(die, 160, t); break;
+// case -160: DO(new, 160, t); break;
+ default: =20
+ add_call_to_generic_SP_update(bb, st, typeof_SP,
+ sizeof_SP, offset_=
SP,
+ /*delta_known*/Tru=
e);
+ break;
+ }
+ } else {
+ /* Put(sp) =3D non-curr */
+ add_call_to_generic_SP_update(bb, st, typeof_SP,
+ sizeof_SP, offset_SP,
+ /*delta_unknown*/False);
+ }
+ } else {
+ // 'Put' of a register other than SP.
+ addStmtToIRSB( bb, st );
+ }
+ break;
=20
- addStmtToIRSB( bb, st );
+ case Ist_PutI:
+ /* PutI or Dirty call which overlaps SP: complain. We can't
+ deal with SP changing in weird ways (well, we can, but no=
t at
+ this time of night). */
+ descr =3D st->Ist.PutI.descr;
+ minoff_ST =3D descr->base;
+ maxoff_ST =3D descr->base + descr->nElems *
+ sizeofIRType(descr->elemTy) - =
1;
+ if (!(offset_SP > maxoff_ST ||=20
+ (offset_SP + sizeof_SP - 1) < minoff_ST)) {
+ VG_(core_panic)("vg_SP_update_pass: PutI which overlaps S=
P");
+ }
+ addStmtToIRSB( bb, st );
+ break;
=20
- // XXX: have to do this after the SP is changed for Memcheck --=
it
- // writes a value to the new stack area, and if the stack needs=
to
- // be extended we have to do that before we can write to it.
- dcall =3D unsafeIRDirty_0_N(=20
- 2/*regparms*/,=20
- "VG_(unknown_SP_update)",=20
- VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
- mkIRExprVec_2( IRExpr_RdTmp(old_SP), st->Ist.Put.dat=
a )=20
- );
- addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
+ case Ist_Dirty: {
+ IRDirty* d =3D st->Ist.Dirty.details;
+ for (j =3D 0; j < d->nFxState; j++) {
+ minoff_ST =3D d->fxState[j].offset;
+ maxoff_ST =3D d->fxState[j].offset + d->fxState[j].size -=
1;
+ if (d->fxState[j].fx =3D=3D Ifx_Read || d->fxState[j].fx =
=3D=3D Ifx_None)
+ break;
+ if (!(offset_SP > maxoff_ST ||
+ (offset_SP + sizeof_SP - 1) < minoff_ST)) {
+ VG_(core_panic)("vg_SP_update_pass: Dirty which overla=
ps SP");
+ }
+ }
+ addStmtToIRSB( bb, st );
+ break;
+ }
=20
- clear_SP_aliases();
- add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
- continue;
+ default:
+ /* Not interesting. Just copy and keep going. */
+ addStmtToIRSB( bb, st );
+ break;
}
-
- case5:
- /* PutI or Dirty call which overlaps SP: complain. We can't
- deal with SP changing in weird ways (well, we can, but not at
- this time of night). */
- if (st->tag =3D=3D Ist_PutI) {
- descr =3D st->Ist.PutI.descr;
- minoff_ST =3D descr->base;
- maxoff_ST =3D descr->base + descr->nElems * sizeofIRType(descr-=
>elemTy) - 1;
- if (!(offset_SP > maxoff_ST || (offset_SP + sizeof_SP - 1) < mi=
noff_ST))
- goto complain;
- }
- if (st->tag =3D=3D Ist_Dirty) {
- d =3D st->Ist.Dirty.details;
- for (j =3D 0; j < d->nFxState; j++) {
- minoff_ST =3D d->fxState[j].offset;
- maxoff_ST =3D d->fxState[j].offset + d->fxState[j].size - 1;
- if (d->fxState[j].fx =3D=3D Ifx_Read || d->fxState[j].fx =3D=
=3D Ifx_None)
- continue;
- if (!(offset_SP > maxoff_ST || (offset_SP + sizeof_SP - 1) <=
minoff_ST))
- goto complain;
- }
- }
-
- /* well, not interesting. Just copy and keep going. */
- addStmtToIRSB( bb, st );
-
} /* for (i =3D 0; i < sb_in->stmts_used; i++) */
=20
return bb;
-
- complain:
- VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP")=
;
-
}
=20
/*------------------------------------------------------------*/
Modified: branches/ORIGIN_TRACKING/memcheck/mc_main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/ORIGIN_TRACKING/memcheck/mc_main.c 2007-01-16 22:04:50 UTC (=
rev 6528)
+++ branches/ORIGIN_TRACKING/memcheck/mc_main.c 2007-01-17 04:35:59 UTC (=
rev 6529)
@@ -31,6 +31,7 @@
*/
=20
// XXX: origin-tracking todo:
+// - keep fixing the SP-delta instrumentation in m_translate.c
// - try recording ExeContexts for stack allocation sites, alter the
// new_mem_stack* events to allow the origin_low32 to be passed in.
// - do timings:
Modified: branches/ORIGIN_TRACKING/memcheck/mc_translate.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/ORIGIN_TRACKING/memcheck/mc_translate.c 2007-01-16 22:04:50 =
UTC (rev 6528)
+++ branches/ORIGIN_TRACKING/memcheck/mc_translate.c 2007-01-17 04:35:59 =
UTC (rev 6529)
@@ -810,6 +810,8 @@
Char perc0[7], perc1[7], perc2[7];
UInt n_total =3D origin_tracking_2 + origin_tracking_1 + origin_track=
ing_0;
=20
+ // XXX: this is all out-of-date now
+ =20
// XXX: there's an off-by-one error in percentify -- if I use 6 inste=
ad
// of 5 here, the buffers get overrun. (there's one in snprintf, too=
)
// [XXX: the snprintf one has been fixed, I think]
|