qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] i386 emulation bug: mov reg, [addr]


From: Clemens Kolbitsch
Subject: [Qemu-devel] i386 emulation bug: mov reg, [addr]
Date: Tue, 15 Dec 2009 19:48:53 +0100
User-agent: KMail/1.12.2 (Linux/2.6.31-16-generic; KDE/4.3.2; x86_64; ; )

Hi list,

I'm experiencing a strange emulation bug with the op-code below. The 
instruction raises a segfault in the application (running on the guest), 
however, if I enable KVM to run the exact same application, no segfault is 
raised.

0x0080023b:       8b 04 65 11 22 33 44    mov regEAX, [0x44332211]

where "11 22 33 44" is just some address. According to gdb (on a 32bit little-
endian machine), this instruction can be disassembled as a "mov address to 
reg-eax".

I have added some debugging code to the disas_insn function in translate.c to 
find out that the code is disassembled to the following blocks:

(NOTE: this debugging comes from an old qemu version where the old TB-style 
code was still used. HOWEVER, the same bug is still happening when used on the 
0.11.0 source branch).

0x0080023b: disassemble 7 bytes (to 0x00800242)
0x001: movl_A0_im 0x44332211
0x002: addl_A0_ESP_s1
0x003: ldl_user_T0_A0
0x004: movl_EAX_T0

So, as you can see, everything seems correct, but there is an additional 
(second) TB that messes everything up. In fact, the segfault happens because 
whatever is in ESP (shifted by one) is added to the address (which might then 
not be a valid address).

As I said, the code might crash in old versions of Qemu just like in the 
0.11.0 source branch and works fine if I use KVM (because the user code is not 
emulated of course).

Since this is such a fundamental problem, I don't quite understand how this 
could stay hidden so long... or maybe there is an error on my side :-/

Any help on this is greatly appreciated!!
--Clemens


---

some additional debugging information: I have traced down the problem to the 
following call in translate.c:

static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int 
*offset_ptr)
{
    ...
    if (s->aflag) {
        /// !!!!!!!!!! we take this path !!!!!!!!!!!!!!
        ...

        if (base == 4) {
            /// !!!!!!!!!! we take this path !!!!!!!!!!!!!!
            havesib = 1;
            code = ldub_code(s->pc++);
            scale = (code >> 6) & 3;
            index = ((code >> 3) & 7) | REX_X(s);
            base = (code & 7);
        }
        base |= REX_B(s);

        switch (mod) {
        ...
        default:
        case 2:
            /// !!!!!!!!!! 4byte load: we take this path !!!!!!!!!!!!!!
            disp = ldl_code(s->pc);
            s->pc += 4;
            break;
        }

        if (base >= 0) {
            /* for correct popl handling with esp */
            ...
        } else {
#ifdef TARGET_X86_64
            if (s->aflag == 2) {
                gen_op_movq_A0_im(disp);
            } else
#endif
            {
                /// !!!!!!!!!! this is still ok, we need the address !!!!!!!
                gen_op_movl_A0_im(disp);
            }
        }
        /* XXX: index == 4 is always invalid */
        if (havesib && (index != 4 || scale != 0)) {
#ifdef TARGET_X86_64
            if (s->aflag == 2) {
                gen_op_addq_A0_reg_sN(scale, index);
            } else
#endif
            {
                /// !!!!!!!!!! this does the evil !!!!!!!!!!!!!!
                gen_op_addl_A0_reg_sN(scale, index);
            }
        }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]