Supplementary explanation about the patch

1. 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. Then you can execute
some GDB commands to reproduce the bug. Below is "result 1" reproducing the
bug.

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

GNU gdb (GDB) 13.0.50.20221204-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target remote localhost:2159
Remote debugging using localhost:2159
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x0000fff0 in ?? ()
(gdb) break *0x7c00
Breakpoint 1 at 0x7c00
(gdb) continue
Continuing.

Breakpoint 1, 0x00007c00 in ?? ()
(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) stepi
0x00007c02 in ?? ()
(gdb) info float
  R7: Valid   0x00000000000000000000 +0
  R6: Valid   0x00000000000000000000 +0
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
=>R0: Valid   0x00000000000000000000 +0

Status Word:         0x0000
                       TOP: 0
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
(gdb) stepi
0x00007c04 in ?? ()
(gdb) info float
=>R7: Valid   0x00000000000000000000 +0
  R6: Valid   0x3fff8000000000000000 +1
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x3800
                       TOP: 7
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
(gdb) stepi
0x00007c06 in ?? ()
(gdb) info float
  R7: Valid   0x00000000000000000000 +0
=>R6: Valid   0x00000000000000000000 +0
  R5: Valid   0x3fff8000000000000000 +1
  R4: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x3000
                       TOP: 6
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
(gdb) stepi
0x00007c08 in ?? ()
(gdb) info float
  R7: Valid   0x00000000000000000000 +0
  R6: Valid   0x00000000000000000000 +0
=>R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x3fff8000000000000000 +1
  R3: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R2: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x2800
                       TOP: 5
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
(gdb) stepi
0x00007c0a in ?? ()
(gdb) info float
  R7: Valid   0x00000000000000000000 +0
  R6: Valid   0x00000000000000000000 +0
  R5: Valid   0x00000000000000000000 +0
=>R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x3fff8000000000000000 +1
  R2: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R1: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407
  R0: Valid   0x4000c90fdaa22168c235 +3.141592653589793239

Status Word:         0x2000
                       TOP: 4
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
(gdb) stepi
0x00007c0c in ?? ()
(gdb) info float
  R7: Valid   0x4000c90fdaa22168c235 +3.141592653589793239
  R6: Valid   0x3ffd9a209a84fbcff799 +0.3010299956639811952
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
=>R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x3fff8000000000000000 +1
  R1: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R0: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407

Status Word:         0x1800
                       TOP: 3
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
(gdb) stepi
0x00007c0e in ?? ()
(gdb) info float
  R7: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407
  R6: Valid   0x4000c90fdaa22168c235 +3.141592653589793239
  R5: Valid   0x3ffd9a209a84fbcff799 +0.3010299956639811952
  R4: Valid   0x3ffeb17217f7d1cf79ac +0.6931471805599453094
  R3: Valid   0x00000000000000000000 +0
=>R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x3fff8000000000000000 +1
  R0: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348

Status Word:         0x1000
                       TOP: 2
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
(gdb) stepi
0x00007c10 in ?? ()
(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 1 ----------

As you can see, the FPU stack rotates every pushing.

2. Cause

There is a cause of the bug in a function "x86_cpu_gdb_read_register" in
"qemu/target/i386/gdbstub.c". GDB receives a command "info float" from stdin
and get values of the all registers containing FPU stack registers from QEMU
to print them. Then, QEMU picks registers in the function to form 'g' packet
to send to GDB. In line 124 of the c source file, absolute indexed FPU stack
registers, namely, R0, ... and R7 , are picked and inserted in 'g' packet.
However, GDB, the packet receiver, extracts FPU stack registers from the
packet and interpret these registers are stack top relative indexed, namely,
ST0, ... and ST7. As a result, GDB can't print FPU stack correctly.

3. Modification

In added lines of this patch, "n" is a register number of a register to
read. And "IDX_FP_REGS" is register number of the first FPU stack register
"R0". So, "r_index" is absolute index of FPU stack register to read. And
"env->fpstt" is a pointer to top of FPU stack. So, "st_index" is stack top
relative index of FPU stack register to read. By applying this modification,
QEMU inserts FPU stack registers ordered by stack top relative index in 'g'
packet.

4. After this patch

Below is "result 2" operating as same as "result 1" after applying this
patch.

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

GNU gdb (GDB) 13.0.50.20221204-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target remote localhost:2159
Remote debugging using localhost:2159
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0x0000fff0 in ?? ()
(gdb) break *0x7c00
Breakpoint 1 at 0x7c00
(gdb) continue
Continuing.

Breakpoint 1, 0x00007c00 in ?? ()
(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) stepi
0x00007c02 in ?? ()
(gdb) info float
  R7: Valid   0x00000000000000000000 +0
  R6: Valid   0x00000000000000000000 +0
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
=>R0: Valid   0x00000000000000000000 +0

Status Word:         0x0000
                       TOP: 0
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
(gdb) stepi
0x00007c04 in ?? ()
(gdb) info float
=>R7: Valid   0x3fff8000000000000000 +1
  R6: Valid   0x00000000000000000000 +0
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x3800
                       TOP: 7
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
(gdb) stepi
0x00007c06 in ?? ()
(gdb) info float
  R7: Valid   0x3fff8000000000000000 +1
=>R6: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R5: Valid   0x00000000000000000000 +0
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x3000
                       TOP: 6
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
(gdb) stepi
0x00007c08 in ?? ()
(gdb) info float
  R7: Valid   0x3fff8000000000000000 +1
  R6: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
=>R5: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407
  R4: Valid   0x00000000000000000000 +0
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x2800
                       TOP: 5
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
(gdb) stepi
0x00007c0a in ?? ()
(gdb) info float
  R7: Valid   0x3fff8000000000000000 +1
  R6: Valid   0x4000d49a784bcd1b8afe +3.321928094887362348
  R5: Valid   0x3fffb8aa3b295c17f0bc +1.442695040888963407
=>R4: Valid   0x4000c90fdaa22168c235 +3.141592653589793239
  R3: Valid   0x00000000000000000000 +0
  R2: Valid   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x2000
                       TOP: 4
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
(gdb) stepi
0x00007c0c in ?? ()
(gdb) info float
  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   0x00000000000000000000 +0
  R1: Valid   0x00000000000000000000 +0
  R0: Valid   0x00000000000000000000 +0

Status Word:         0x1800
                       TOP: 3
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
(gdb) stepi
0x00007c0e in ?? ()
(gdb) info float
  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

Status Word:         0x1000
                       TOP: 2
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
(gdb) stepi
0x00007c10 in ?? ()
(gdb) info float
  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

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 ----------

Reply via email to