opt/qemu/qemu-0.7.2-dyngen-check-stack-clobbers.patch
2006-03-30 14:11:17 +00:00

138 lines
4.4 KiB
Diff

2005-11-11 Gwenole Beauchesne <gbeauchesne@mandriva.com>
* Check for stack clobbers in functions using GOTO_LABEL_PARAM().
--- qemu-0.7.2/dyngen.c.dyngen-check-stack-clobbers 2005-11-11 16:26:33.000000000 +0100
+++ qemu-0.7.2/dyngen.c 2005-11-11 17:30:29.000000000 +0100
@@ -1414,6 +1414,9 @@ int arm_emit_ldr_info(const char *name,
#define FLAG_TARGET (1 << 3)
/* This is a magic instruction that needs fixing up. */
#define FLAG_EXIT (1 << 4)
+/* This instruction clobbers the stack pointer. */
+/* XXX only supports push, pop, add/sub $imm,%esp */
+#define FLAG_STACK (1 << 5)
#define MAX_EXITS 5
static void
@@ -1454,6 +1457,7 @@ trace_i386_insn (const char *name, uint8
int is_jmp;
int is_exit;
int is_pcrel;
+ int is_stack;
int immed;
int seen_rexw;
int32_t disp;
@@ -1476,6 +1480,7 @@ trace_i386_insn (const char *name, uint8
is_exit = 0;
seen_rexw = 0;
is_pcrel = 0;
+ is_stack = 0;
while (is_prefix) {
op = ptr[insn_size];
@@ -1522,6 +1527,7 @@ trace_i386_insn (const char *name, uint8
switch (op & 0x7) {
case 0: /* push fs/gs */
case 1: /* pop fs/gs */
+ is_stack = 1;
case 2: /* cpuid/rsm */
modrm = 0;
break;
@@ -1594,6 +1600,7 @@ trace_i386_insn (const char *name, uint8
#endif
case 5: /* push/pop general register. */
modrm = 0;
+ is_stack = 1;
break;
case 6:
@@ -1601,6 +1608,7 @@ trace_i386_insn (const char *name, uint8
case 0: /* pusha */
case 1: /* popa */
modrm = 0;
+ is_stack = 1;
break;
case 2: /* bound */
case 3: /* arpl */
@@ -1620,10 +1628,12 @@ trace_i386_insn (const char *name, uint8
case 8: /* push immediate */
immed = op_size;
modrm = 0;
+ is_stack = 1;
break;
case 10: /* push 8-bit immediate */
immed = 1;
modrm = 0;
+ is_stack = 1;
break;
case 9: /* imul immediate */
immed = op_size;
@@ -1653,8 +1663,22 @@ trace_i386_insn (const char *name, uint8
immed = op_size;
else
immed = 1;
+ if (op == 0x81 || op == 0x83) {
+ /* add, sub */
+ op = ptr[insn_size];
+ switch ((op >> 3) & 7) {
+ case 0:
+ case 5:
+ is_stack = (op & 7) == 4;
+ break;
+ }
+ }
}
- /* else test, xchg, mov, lea or pop general. */
+ else if ((op & 0xf) == 0xf) {
+ /* pop general. */
+ is_stack = 1;
+ }
+ /* else test, xchg, mov, lea. */
break;
case 9:
@@ -1904,6 +1928,9 @@ trace_i386_insn (const char *name, uint8
if (is_exit)
flags[insn] |= FLAG_EXIT;
+ if (is_stack)
+ flags[insn] |= FLAG_STACK;
+
if (!(is_jmp || is_ret || is_exit))
flags[insn + insn_size] |= FLAG_INSN;
}
@@ -1924,6 +1951,7 @@ static int trace_i386_op(const char * na
int num_exits;
int len;
int last_insn;
+ int stack_clobbered;
len = *plen;
flags = malloc(len + 1);
@@ -1947,6 +1975,7 @@ static int trace_i386_op(const char * na
retpos = -1;
num_exits = 0;
last_insn = 0;
+ stack_clobbered = 0;
for (insn = 0; insn < len; insn++) {
if (flags[insn] & FLAG_RET) {
/* ??? In theory it should be possible to handle multiple return
@@ -1956,6 +1985,8 @@ static int trace_i386_op(const char * na
retpos = insn;
}
if (flags[insn] & FLAG_EXIT) {
+ if (stack_clobbered)
+ error("Stack clobbered in %s", name);
if (num_exits == MAX_EXITS)
error("Too many block exits in %s", name);
exit_addrs[num_exits] = insn;
@@ -1963,6 +1994,8 @@ static int trace_i386_op(const char * na
}
if (flags[insn] & FLAG_INSN)
last_insn = insn;
+ if (flags[insn] & FLAG_STACK)
+ stack_clobbered = 1;
}
exit_addrs[num_exits] = -1;