tcg: Add support for debugging leakage of temporaries

Add support (if CONFIG_DEBUG_TCG is defined) for debugging leakage
of temporary variables. Generally any temporaries created by
a target while it is translating an instruction should be freed
by the end of that instruction; otherwise carefully crafted
guest code could cause TCG to run out of temporaries and assert.
By calling tcg_check_temp_count() after each instruction we can
check that we are not leaking temporaries in this way.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
Peter Maydell 2011-03-06 21:39:53 +00:00 committed by Aurelien Jarno
parent 6ed221b637
commit 27bfd83c33
2 changed files with 49 additions and 0 deletions

View File

@ -450,6 +450,10 @@ static inline int tcg_temp_new_internal(TCGType type, int temp_local)
s->nb_temps++; s->nb_temps++;
} }
} }
#if defined(CONFIG_DEBUG_TCG)
s->temps_in_use++;
#endif
return idx; return idx;
} }
@ -475,6 +479,13 @@ static inline void tcg_temp_free_internal(int idx)
TCGTemp *ts; TCGTemp *ts;
int k; int k;
#if defined(CONFIG_DEBUG_TCG)
s->temps_in_use--;
if (s->temps_in_use < 0) {
fprintf(stderr, "More temporaries freed than allocated!\n");
}
#endif
assert(idx >= s->nb_globals && idx < s->nb_temps); assert(idx >= s->nb_globals && idx < s->nb_temps);
ts = &s->temps[idx]; ts = &s->temps[idx];
assert(ts->temp_allocated != 0); assert(ts->temp_allocated != 0);
@ -528,6 +539,27 @@ TCGv_i64 tcg_const_local_i64(int64_t val)
return t0; return t0;
} }
#if defined(CONFIG_DEBUG_TCG)
void tcg_clear_temp_count(void)
{
TCGContext *s = &tcg_ctx;
s->temps_in_use = 0;
}
int tcg_check_temp_count(void)
{
TCGContext *s = &tcg_ctx;
if (s->temps_in_use) {
/* Clear the count so that we don't give another
* warning immediately next time around.
*/
s->temps_in_use = 0;
return 1;
}
return 0;
}
#endif
void tcg_register_helper(void *func, const char *name) void tcg_register_helper(void *func, const char *name)
{ {
TCGContext *s = &tcg_ctx; TCGContext *s = &tcg_ctx;

View File

@ -323,6 +323,10 @@ struct TCGContext {
int64_t restore_count; int64_t restore_count;
int64_t restore_time; int64_t restore_time;
#endif #endif
#ifdef CONFIG_DEBUG_TCG
int temps_in_use;
#endif
}; };
extern TCGContext tcg_ctx; extern TCGContext tcg_ctx;
@ -392,6 +396,19 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void)
void tcg_temp_free_i64(TCGv_i64 arg); void tcg_temp_free_i64(TCGv_i64 arg);
char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg); char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
#if defined(CONFIG_DEBUG_TCG)
/* If you call tcg_clear_temp_count() at the start of a section of
* code which is not supposed to leak any TCG temporaries, then
* calling tcg_check_temp_count() at the end of the section will
* return 1 if the section did in fact leak a temporary.
*/
void tcg_clear_temp_count(void);
int tcg_check_temp_count(void);
#else
#define tcg_clear_temp_count() do { } while (0)
#define tcg_check_temp_count() 0
#endif
void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf); void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
#define TCG_CT_ALIAS 0x80 #define TCG_CT_ALIAS 0x80