summaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-03-06 21:39:53 +0000
committerAurelien Jarno <aurelien@aurel32.net>2011-03-07 09:26:06 +0100
commit27bfd83c336283d1f7a5345ee386c4cd7b80db61 (patch)
tree21e8fb770030f606b15f09087262e2db2e3a7549 /tcg
parent6ed221b637713aec903136e3061e714fa4809bdd (diff)
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>
Diffstat (limited to 'tcg')
-rw-r--r--tcg/tcg.c32
-rw-r--r--tcg/tcg.h17
2 files changed, 49 insertions, 0 deletions
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 5dd6a2c61..8748c05b5 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -450,6 +450,10 @@ static inline int tcg_temp_new_internal(TCGType type, int temp_local)
s->nb_temps++;
}
}
+
+#if defined(CONFIG_DEBUG_TCG)
+ s->temps_in_use++;
+#endif
return idx;
}
@@ -475,6 +479,13 @@ static inline void tcg_temp_free_internal(int idx)
TCGTemp *ts;
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);
ts = &s->temps[idx];
assert(ts->temp_allocated != 0);
@@ -528,6 +539,27 @@ TCGv_i64 tcg_const_local_i64(int64_t val)
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)
{
TCGContext *s = &tcg_ctx;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index e1afde26b..3fab8d6c2 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -323,6 +323,10 @@ struct TCGContext {
int64_t restore_count;
int64_t restore_time;
#endif
+
+#ifdef CONFIG_DEBUG_TCG
+ int temps_in_use;
+#endif
};
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);
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);
#define TCG_CT_ALIAS 0x80