|
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 |
[Prev in Thread] | Current Thread | [Next in Thread] |