From: Julian Seward Date: Wed, 14 Jul 2004 22:36:10 +0000 (+0000) Subject: First part of IR sanity checking: def/use checks. X-Git-Tag: svn/VALGRIND_3_0_1^2~1249 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7559c79ca8201e213fbc6c9d64b3f40d9c3b9b28;p=thirdparty%2Fvalgrind.git First part of IR sanity checking: def/use checks. git-svn-id: svn://svn.valgrind.org/vex/trunk@85 --- diff --git a/VEX/priv/ir/ir_defs.c b/VEX/priv/ir/ir_defs.c index c94450f231..33c9eafb55 100644 --- a/VEX/priv/ir/ir_defs.c +++ b/VEX/priv/ir/ir_defs.c @@ -235,7 +235,9 @@ void ppIRTypeEnv ( IRTypeEnv* env ) { void ppIRBB ( IRBB* bb ) { IRStmt* s; + vex_printf("IRBB {\n"); ppIRTypeEnv(bb->tyenv); + vex_printf("\n"); for (s = bb->stmts; s; s = s->link) { vex_printf( " "); ppIRStmt(s); @@ -245,7 +247,7 @@ void ppIRBB ( IRBB* bb ) ppIRJumpKind(bb->jumpkind); vex_printf( "} "); ppIRExpr( bb->next ); - vex_printf( "\n"); + vex_printf( "\n}\n"); } @@ -474,14 +476,118 @@ IRType typeOfIRExpr ( IRTypeEnv* tyenv, IRExpr* e ) /* Checks: Everything is type-consistent. No ill-typed anything. + The target address at the end of the BB is a 32- or 64- + bit expression, depending on the guest's word size. Each temp is assigned only once, before its uses. + */ +static +__attribute((noreturn)) +void sanityCheckFail ( IRBB* bb, IRStmt* stmt, Char* what ) +{ + vex_printf("\nIR SANITY CHECK FAILURE\n\n"); + ppIRBB(bb); + if (stmt) { + vex_printf("\nIN STATEMENT:\n\n"); + ppIRStmt(stmt); + } + vex_printf("\n\nERROR = %s\n\n", what ); + vpanic("sanityCheckFail: exiting due to bad IR"); +} - */ -void sanityCheckIRBB ( IRBB* bb ) +/* Traverse a Stmt/Expr, inspecting IRTemp uses. Report any out of + range ones. Report any which are read and for which the current + def_count is zero. */ + +static +void useBeforeDef_Expr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts ) { + Int i; + switch (expr->tag) { + case Iex_Get: + break; + case Iex_Tmp: + if (expr->Iex.Tmp.tmp < 0 || expr->Iex.Tmp.tmp >= bb->tyenv->types_used) + sanityCheckFail(bb,stmt, "out of range Temp in IRExpr"); + if (def_counts[expr->Iex.Tmp.tmp] < 1) + sanityCheckFail(bb,stmt, "IRTemp def before use in IRExpr"); + break; + case Iex_Binop: + useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg1,def_counts); + useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg2,def_counts); + break; + case Iex_Unop: + useBeforeDef_Expr(bb,stmt,expr->Iex.Unop.arg,def_counts); + break; + case Iex_LDle: + useBeforeDef_Expr(bb,stmt,expr->Iex.LDle.addr,def_counts); + break; + case Iex_Const: + break; + case Iex_CCall: + for (i = 0; expr->Iex.CCall.args[i]; i++) + useBeforeDef_Expr(bb,stmt,expr->Iex.CCall.args[i],def_counts); + break; + } +} + +static +void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts ) +{ + switch (stmt->tag) { + case Ist_Put: + if (stmt->Ist.Put.guard) + useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.guard,def_counts); + useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.expr,def_counts); + break; + case Ist_Tmp: + useBeforeDef_Expr(bb,stmt,stmt->Ist.Tmp.expr,def_counts); + break; + case Ist_STle: + useBeforeDef_Expr(bb,stmt,stmt->Ist.STle.addr,def_counts); + useBeforeDef_Expr(bb,stmt,stmt->Ist.STle.data,def_counts); + break; + case Ist_Exit: + useBeforeDef_Expr(bb,stmt,stmt->Ist.Exit.cond,def_counts); + break; + default: + vpanic("useBeforeDef_Stmt"); + } +} + + +void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) +{ + Int i; + IRStmt* stmt; + Int n_temps = bb->tyenv->types_used; + Int* def_counts = LibVEX_Alloc(n_temps * sizeof(Int)); + + vassert(guest_word_size == Ity_I32 + || guest_word_size == Ity_I64); + + for (i = 0; i < n_temps; i++) + def_counts[i] = 0; + + /* Count the defs of each temp. Only one def is allowed. + Also, check that each used temp has already been defd. */ + for (stmt = bb->stmts; stmt; stmt=stmt->link) { + useBeforeDef_Stmt(bb,stmt,def_counts); + if (stmt->tag == Ist_Tmp) { + if (stmt->Ist.Tmp.tmp < 0 || stmt->Ist.Tmp.tmp >= n_temps) + sanityCheckFail(bb, stmt, "Invalid temp in Tmp assignment"); + def_counts[stmt->Ist.Tmp.tmp]++; + if (def_counts[stmt->Ist.Tmp.tmp] > 1) + sanityCheckFail(bb, stmt, "Tmp assigned more than once"); + } + } + + for (i = 0; i < n_temps; i++) + vex_printf("%d ", def_counts[i]); + vex_printf("\n"); + } /*---------------------------------------------------------------*/ diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index 33b68051a9..fd8aec4ac3 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -138,6 +138,7 @@ TranslateResult LibVEX_Translate ( LibVEX_Clear(False); return TransAccessFail; } + sanityCheckIRBB(irbb, Ity_I32); return TransOK; /* Get the thing instrumented. */ if (instrument) diff --git a/VEX/priv/main/vex_util.c b/VEX/priv/main/vex_util.c index 73d70a65eb..cfb2c5ec62 100644 --- a/VEX/priv/main/vex_util.c +++ b/VEX/priv/main/vex_util.c @@ -43,12 +43,13 @@ static ULong storage_count_allocs_TOT = 0; void* LibVEX_Alloc ( Int nbytes ) { vassert(vex_initdone); - vassert(nbytes > 0); + vassert(nbytes >= 0); if (vex_valgrind_support) { /* ugly hack */ extern void* malloc ( int ); return malloc(nbytes); } else { + if (nbytes == 0) nbytes = 8; nbytes = (nbytes + 7) & ~7; if (storage_used + nbytes > N_STORAGE_BYTES) vpanic("VEX storage exhausted.\n" diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 5c382ab3f4..81a3d9806f 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -310,6 +310,8 @@ extern IRType lookupIRTypeEnv ( IRTypeEnv*, IRTemp ); /* What is the type of this expression? */ extern IRType typeOfIRExpr ( IRTypeEnv*, IRExpr* ); +/* Sanity check a BB of IR */ +extern void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ); #endif /* ndef __LIBVEX_IR_H */