qemu-devel
[Top][All Lists]
Advanced

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

RE: [PATCH] gdb-xml: Fix size of EFER register on i386 architecture when


From: 伊藤 太清
Subject: RE: [PATCH] gdb-xml: Fix size of EFER register on i386 architecture when debugged by GDB
Date: Sat, 5 Nov 2022 03:14:00 +0000

Thanks for the reply. Below are details about the patch.

 

1. A bug

 

GDB cannot print the x87 FPU registers correctly when the GDB is debugging

an OS working on qemu-system-i386.

 

1.1 My host environment

 

Ubuntu 22.04.1 LTS

 

1.2 Reproduction of the bug

 

The following 3 files are needed to reproduce the bug.

 

* test_os.s

* test_os.ld

* Makefile

 

And the following 2 tools, too.

 

* build-essential

* gdb

 

The contents of the above files are below.

 

---------- Begin of test_os.s ----------

 

            .code16

            .text

main:

            fninit  # Initialize the FPU

            fld1    # Push 1.0

            fldl2t  # Push log 2 10

            fldl2e # Push log 2 e

            fldpi   # Push pi

            fldlg2 # Push log 10 2

            fldln2 # Push log e 2

            fldz     # Push 0.0

loop:

            hlt

            jmp loop

 

---------- End of test_os.s ----------

 

---------- Begin of test_os.ld ----------

 

OUTPUT_FORMAT("binary");

 

BASE = 0x00007c00;

 

SECTIONS

{

            . = BASE;

            .text :

            {

                       test_os.o(.text)

            }

            . = BASE;

            . += 0x00000200;

            . -= 0x00000002;

            .boot_sector_sign :

            {

                       BYTE(0x55);

                       BYTE(0xaa);

            }

            /DISCARD/ :

            {

                       *(.eh_frame)

                       *(.note.gnu.property)

            }

}

 

---------- End of test_os.ld ----------

 

---------- Begin of Makefile ----------

 

TEST_OS_NAME = test_o

TEST_OS_NAME = test_os

TEST_OS_ASM = $(TEST_OS_NAME).s

TEST_OS_IMG = $(TEST_OS_NAME).img

TEST_OS_LNK = $(TEST_OS_NAME).ld

TEST_OS_MAP = $(TEST_OS_NAME).map

TEST_OS_OBJ = $(TEST_OS_NAME).o

 

all: $(TEST_OS_IMG)

 

test: $(TEST_OS_IMG)

            (qemu-system-i386 -boot order=a \

            -drive file=$<,format=raw,if=floppy \

            -S -gdb tcp::2159 -vnc localhost:0 &) && \

            gdb

 

$(TEST_OS_IMG): $(TEST_OS_OBJ) $(TEST_OS_LNK)

            ld $< -Map $(TEST_OS_MAP) -o $@ -T $(word 2, $^)

 

$(TEST_OS_OBJ): $(TEST_OS_ASM)

            gcc $^ -c -nostdlib -o $@ -Wall -Wextra

 

---------- End of Makefile ----------

 

Put these files on a same directory. "test_os.s" is source code of tiny OS

to run on QEMU. The OS consists only a boot sector. It initialize x87 FPU

and pushes some floating point values onto x87 FPU stack. "test_os.ld" is

its linker script. And you can make "test_os.img", a raw image of the OS.

Now, there are all things to reproduce the bug. You can "make test" to let

QEMU run the OS and wait for GDB, then GDB will start. Below is "result 1"

reproducing the bug.

 

---------- Begin of result 1 ----------

 

$ make test

(gdb) target remote localhost:2159

(gdb) break *0x7c00

(gdb) continue

(gdb) x/10i $eip

=> 0x7c00:      fninit

   0x7c02:      fld1

   0x7c04:      fldl2t

   0x7c06:      fldl2e

   0x7c08:      fldpi

   0x7c0a:      fldlg2

   0x7c0c:      fldln2

   0x7c0e:      fldz

   0x7c10:      hlt

   0x7c11:      jmp    0x7c10

(gdb) break *0x7c10

(gdb) continue

(gdb) info float

  R7: Valid   0x0000037f3fff80000000 +9.185555460266999444e-4934 Denormal

  R6: Valid   0x000000004000d49a784b +2.56521115372749819e-4937  Denormal

  R5: Valid   0xcd1b8afe3fffb8aa3b29 -1.960870532096122377e+1010

  R4: Valid   0x5c17f0bc4000c90fdaa2 +1.914514747773691148e+2165

  R3: Valid   0x2168c2353ffd9a209a84 +6.533729021523866343e-2358

  R2: Valid   0xfbcff7993ffeb17217f7 -4.548119628708025252e+4609

  R1: Valid   0xd1cf79ac000000000000 Unsupported

=>R0: Valid   0x00000000000000000000 +0

 

Status Word:         0x0000

                       TOP: 0

Control Word:        0x0800

                       PC: Single Precision (24-bits)

                       RC: Round up

Tag Word:            0x0000

Instruction Pointer: 0x00:0x00000000

Operand Pointer:     0x00:0x00000000

Opcode:              0x0000

 

---------- End of result 1 ----------

 

First, in GDB interface, connect localhost:2159 where QEMU is waiting for

GDB. Second, Proceed to 0x7c00 and confirm there are intentional

instructions. Finally, Proceed to 0x7c10 and confirm contents of the x87

FPU registers. There are values different from what the OS pushed in

registers from "R0" to "R7", the x87 FPU stack. Furthermore, the control

word seems to be wrong. The first instruction "fninit" in the OS makes the

control word 0x037f but it is 0x0800 in the above result.

 

2. Cause

 

There is a cause in exchanging 'g' packet between QEMU and GDB. This packet

sends registers of machine emulated by QEMU to GDB. And its format is

defined in "qemu/gdb-xml/i386-32bit.xml". Size of EFER register is defined

in two places, line 113 and 129.

 

---------- qemu/gdb-xml/i386-32bit.xml line 113 ----------

 

  <flags id="i386_efer" size="8">

 

----------------------------------------------------------

 

The above line says size of EFER is 8 bytes.

 

---------- qemu/gdb-xml/i386-32bit.xml line 129 ----------

 

  <reg name="efer" bitsize="32" type="i386_efer"/>

 

----------------------------------------------------------

 

The above line says size of EFER is 32 bits. These lines contradict each

other. QEMU, the packet sender, assign 4 bytes for EFER in 'g' packet based

on the line 113. GDB, the packet receiver, extract 8 bytes for EFER in 'g'

packet based on the line 129. As a result, all registers located after EFER

in 'g' packet has been shifted 4 bytes in GDB.

 

3. Modification

 

Unify size of EFER 4 bytes.

 

4. Result

 

Below is "result 2" doing same operation as "result 1" using the modified

xml.

 

---------- Begin of result 2 ----------

 

$ make test

(gdb) target remote localhost:2159

(gdb) break *0x7c00

(gdb) continue

(gdb) x/10i $eip

=> 0x7c00:      fninit

   0x7c02:      fld1

   0x7c04:      fldl2t

   0x7c06:      fldl2e

   0x7c08:      fldpi

   0x7c0a:      fldlg2

   0x7c0c:      fldln2

   0x7c0e:      fldz

   0x7c10:      hlt

   0x7c11:      jmp    0x7c10

(gdb) break *0x7c10

(gdb) continue

(gdb) info float

  R7: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348

  R6: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407

  R5: Valid   0x4000c90fdaa22168c235 +3.141592653589793239

  R4: Valid   0x3ffd9a209a84fbcff799 +0.3010299956639811952

  R3: Valid   0x3ffeb17217f7d1cf79ac +0.6931471805599453094

  R2: Valid   0x00000000000000000000 +0

=>R1: Valid   0x00000000000000000000 +0

  R0: Valid   0x3fff8000000000000000 +1

 

Status Word:         0x0800

                       TOP: 1

Control Word:        0x037f   IM DM ZM OM UM PM

                       PC: Extended Precision (64-bits)

                       RC: Round to nearest

Tag Word:            0x0000

Instruction Pointer: 0x00:0x00000000

Operand Pointer:     0x00:0x00000000

Opcode:              0x0000

 

---------- End of result 2 ----------

 

There are more reasonable values in the FPU stack than previous. Control

word gets correct, too. But order of FPU stack is wrong. Correct FPU stack

should be like below.

 

---------- Begin of Correct FPU stack ----------

 

  R7: Valid   0x3fff8000000000000000 +1

  R6: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348

  R5: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407

  R4: Valid   0x4000c90fdaa22168c235 +3.141592653589793239

  R3: Valid   0x3ffd9a209a84fbcff799 +0.3010299956639811952

  R2: Valid   0x3ffeb17217f7d1cf79ac +0.6931471805599453094

=>R1: Valid   0x00000000000000000000 +0

  R0: Valid   0x00000000000000000000 +0

 

---------- End of Correct FPU stack ----------

 

The floor of the stack is "R7" and should have value "1.0" that the OS

pushed first. The top of the stack is "R1" and should have value "0.0", the

last pushed value. The stack of the second result seems to have been

rotated up 1 element. I think there are confusing between physical

registers from "R0" to "R7" and stack top relative pointer from "ST0" to

"ST7". But I think this problem should be handled as another bug. I am

looking into this problem and have not yet determined whether should I send

a patch to QEMU or GDB yet. So this patch includes only modification of

size of EFER register.

 

Taisei Ito

 

Sent from Mail for Windows

 


From: Alex Bennée <alex.bennee@linaro.org>
Sent: Friday, November 4, 2022 12:59:24 AM
To: TaiseiIto <taisei1212@outlook.jp>
Cc: qemu-devel@nongnu.org <qemu-devel@nongnu.org>; f4bug@amsat.org <f4bug@amsat.org>
Subject: Re: [PATCH] gdb-xml: Fix size of EFER register on i386 architecture when debugged by GDB
 

TaiseiIto <taisei1212@outlook.jp> writes:

> Before this commit, there were contradictory descriptions about size of EFER
> register.
> Line 113 says the size is 8 bytes.
> Line 129 says the size is 4 bytes.
>
> As a result, when GDB is debugging an OS running on QEMU, the GDB cannot
> read 'g' packets correctly. This 'g' packet transmits values of each
> registers of machine emulated by QEMU to GDB. QEMU, the packet sender,
> assign 4 bytes for EFER in 'g' packet based on the line 113.
> GDB, the packet receiver, extract 8 bytes for EFER in 'g' packet based on
> the line 129. Therefore, all registers located behind EFER in 'g' packet
> has been shifted 4 bytes in GDB.

I can't get the failure to read in my case:

  ./qemu-system-i386 -monitor none -display none \
    -chardev stdio,id=out -device isa-debugcon,chardev=out \
    -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
    -kernel ./tests/tcg/i386-softmmu/memory -s -S

and then with gdb:

  ➜  gdb ./tests/tcg/i386-softmmu/memory -ex "target remote localhost:1234"
  Reading symbols from ./tests/tcg/i386-softmmu/memory...
  Remote debugging using localhost:1234
  0x0000fff0 in ?? ()
  (gdb) info registers efer
  efer           0x0                 [ ]

What am I missing?

>
> After this commit, GDB can read 'g' packets correctly.
>
> Signed-off-by: TaiseiIto <taisei1212@outlook.jp>
> ---
>  gdb-xml/i386-32bit.xml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gdb-xml/i386-32bit.xml b/gdb-xml/i386-32bit.xml
> index 872fcea9c2..7a66a02b67 100644
> --- a/gdb-xml/i386-32bit.xml
> +++ b/gdb-xml/i386-32bit.xml
> @@ -110,7 +110,7 @@
>        <field name="PKE" start="22" end="22"/>
>    </flags>

> -  <flags id="i386_efer" size="8">
> +  <flags id="i386_efer" size="4">
>        <field name="TCE" start="15" end="15"/>
>        <field name="FFXSR" start="14" end="14"/>
>        <field name="LMSLE" start="13" end="13"/>


--
Alex Bennée

reply via email to

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