]>
Commit | Line | Data |
---|---|---|
891bbdf5 AM |
1 | 2005-11-11 Gwenole Beauchesne <gbeauchesne@mandriva.com> |
2 | ||
3 | * Check for stack clobbers in functions using GOTO_LABEL_PARAM(). | |
4 | ||
5 | --- qemu-0.7.2/dyngen.c.dyngen-check-stack-clobbers 2005-11-11 16:26:33.000000000 +0100 | |
6 | +++ qemu-0.7.2/dyngen.c 2005-11-11 17:30:29.000000000 +0100 | |
7 | @@ -1414,6 +1414,9 @@ int arm_emit_ldr_info(const char *name, | |
8 | #define FLAG_TARGET (1 << 3) | |
9 | /* This is a magic instruction that needs fixing up. */ | |
10 | #define FLAG_EXIT (1 << 4) | |
11 | +/* This instruction clobbers the stack pointer. */ | |
12 | +/* XXX only supports push, pop, add/sub $imm,%esp */ | |
13 | +#define FLAG_STACK (1 << 5) | |
14 | #define MAX_EXITS 5 | |
15 | ||
16 | static void | |
17 | @@ -1454,6 +1457,7 @@ trace_i386_insn (const char *name, uint8 | |
18 | int is_jmp; | |
19 | int is_exit; | |
20 | int is_pcrel; | |
21 | + int is_stack; | |
22 | int immed; | |
23 | int seen_rexw; | |
24 | int32_t disp; | |
25 | @@ -1476,6 +1480,7 @@ trace_i386_insn (const char *name, uint8 | |
26 | is_exit = 0; | |
27 | seen_rexw = 0; | |
28 | is_pcrel = 0; | |
29 | + is_stack = 0; | |
30 | ||
31 | while (is_prefix) { | |
32 | op = ptr[insn_size]; | |
33 | @@ -1522,6 +1527,7 @@ trace_i386_insn (const char *name, uint8 | |
34 | switch (op & 0x7) { | |
35 | case 0: /* push fs/gs */ | |
36 | case 1: /* pop fs/gs */ | |
37 | + is_stack = 1; | |
38 | case 2: /* cpuid/rsm */ | |
39 | modrm = 0; | |
40 | break; | |
41 | @@ -1594,6 +1600,7 @@ trace_i386_insn (const char *name, uint8 | |
42 | #endif | |
43 | case 5: /* push/pop general register. */ | |
44 | modrm = 0; | |
45 | + is_stack = 1; | |
46 | break; | |
47 | ||
48 | case 6: | |
49 | @@ -1601,6 +1608,7 @@ trace_i386_insn (const char *name, uint8 | |
50 | case 0: /* pusha */ | |
51 | case 1: /* popa */ | |
52 | modrm = 0; | |
53 | + is_stack = 1; | |
54 | break; | |
55 | case 2: /* bound */ | |
56 | case 3: /* arpl */ | |
57 | @@ -1620,10 +1628,12 @@ trace_i386_insn (const char *name, uint8 | |
58 | case 8: /* push immediate */ | |
59 | immed = op_size; | |
60 | modrm = 0; | |
61 | + is_stack = 1; | |
62 | break; | |
63 | case 10: /* push 8-bit immediate */ | |
64 | immed = 1; | |
65 | modrm = 0; | |
66 | + is_stack = 1; | |
67 | break; | |
68 | case 9: /* imul immediate */ | |
69 | immed = op_size; | |
70 | @@ -1653,8 +1663,22 @@ trace_i386_insn (const char *name, uint8 | |
71 | immed = op_size; | |
72 | else | |
73 | immed = 1; | |
74 | + if (op == 0x81 || op == 0x83) { | |
75 | + /* add, sub */ | |
76 | + op = ptr[insn_size]; | |
77 | + switch ((op >> 3) & 7) { | |
78 | + case 0: | |
79 | + case 5: | |
80 | + is_stack = (op & 7) == 4; | |
81 | + break; | |
82 | + } | |
83 | + } | |
84 | } | |
85 | - /* else test, xchg, mov, lea or pop general. */ | |
86 | + else if ((op & 0xf) == 0xf) { | |
87 | + /* pop general. */ | |
88 | + is_stack = 1; | |
89 | + } | |
90 | + /* else test, xchg, mov, lea. */ | |
91 | break; | |
92 | ||
93 | case 9: | |
94 | @@ -1904,6 +1928,9 @@ trace_i386_insn (const char *name, uint8 | |
95 | if (is_exit) | |
96 | flags[insn] |= FLAG_EXIT; | |
97 | ||
98 | + if (is_stack) | |
99 | + flags[insn] |= FLAG_STACK; | |
100 | + | |
101 | if (!(is_jmp || is_ret || is_exit)) | |
102 | flags[insn + insn_size] |= FLAG_INSN; | |
103 | } | |
104 | @@ -1924,6 +1951,7 @@ static int trace_i386_op(const char * na | |
105 | int num_exits; | |
106 | int len; | |
107 | int last_insn; | |
108 | + int stack_clobbered; | |
109 | ||
110 | len = *plen; | |
111 | flags = malloc(len + 1); | |
112 | @@ -1947,6 +1975,7 @@ static int trace_i386_op(const char * na | |
113 | retpos = -1; | |
114 | num_exits = 0; | |
115 | last_insn = 0; | |
116 | + stack_clobbered = 0; | |
117 | for (insn = 0; insn < len; insn++) { | |
118 | if (flags[insn] & FLAG_RET) { | |
119 | /* ??? In theory it should be possible to handle multiple return | |
120 | @@ -1956,6 +1985,8 @@ static int trace_i386_op(const char * na | |
121 | retpos = insn; | |
122 | } | |
123 | if (flags[insn] & FLAG_EXIT) { | |
124 | + if (stack_clobbered) | |
125 | + error("Stack clobbered in %s", name); | |
126 | if (num_exits == MAX_EXITS) | |
127 | error("Too many block exits in %s", name); | |
128 | exit_addrs[num_exits] = insn; | |
129 | @@ -1963,6 +1994,8 @@ static int trace_i386_op(const char * na | |
130 | } | |
131 | if (flags[insn] & FLAG_INSN) | |
132 | last_insn = insn; | |
133 | + if (flags[insn] & FLAG_STACK) | |
134 | + stack_clobbered = 1; | |
135 | } | |
136 | ||
137 | exit_addrs[num_exits] = -1; |