On Wed, May 5, 2021 at 4:12 PM Borislav Petkov <bp@xxxxxxxxx> wrote: > > On Wed, May 05, 2021 at 03:11:18PM -0700, Andy Lutomirski wrote: > > Since I'm not holding my breath, please at least keep in mind that > > anything you do here is merely a heuristic, cannot be fully correct, > > and then whenever gdb determines that a thread group or a thread is > > "32-bit", gdb is actually deciding to operate in a degraded mode for > > that task, is not accurately representing the task state, and is at > > risk of crashing, malfunctioning, or crashing the inferior due to its > > incorrect assumptions. If you have ever attached gdb to QEMU's > > gdbserver and tried to debug the early boot process of a 64-bit Linux > > kernel, you may have encountered this class of bugs. gdb works very, > > very poorly for this use case. > > So we were talking about this with toolchain folks today and they gave > me this example: > > Imagine you've stopped the target this way: > > <insn><-- stopped here > <insn> > <mode changing insn> > <insn> > <insn> > ... > > now, if you dump rIP and say, rIP + the 10 following insns at the place > you've stopped it, gdb cannot know that 2 insns further into the stream > a > > <mode changing insn> > > is coming and it should change the disassembly of the insns after that > <mode changing insn> to the new mode. Unless it goes and inspects all > further instructions and disassembles them and analyzes the flow... That's fine. x86 machine code is like this. You also can't disassemble instructions before rIP accurately either. > > So what you can do is > > (gdb) set arch ... > > at the <mode changing insn> to the mode you're changing to. > > Dunno, maybe I'm missing something but this sounds like without user > help gdb can only assume things. In the tools/testing/x86/selftests directory, edited slightly for brevity: $ gdb ./test_syscall_vdso_32 (gdb) b call64_from_32 Breakpoint 1 at 0x80499ef: file thunks_32.S, line 19. (gdb) display/i $pc 1: x/i $pc <error: No registers.> (gdb) r Starting program: /home/luto/apps/linux/tools/testing/selftests/x86/test_syscall_vdso_32 ... [RUN] Executing 6-argument 32-bit syscall via VDSO Breakpoint 1, call64_from_32 () at thunks_32.S:19 19 mov 4(%esp), %eax 1: x/i $pc => 0x80499ef <call64_from_32>: mov 0x4(%esp),%eax (gdb) si 22 push %ecx 1: x/i $pc => 0x80499f3 <call64_from_32+4>: push %ecx (gdb) call64_from_32 () at thunks_32.S:23 23 push %edx 1: x/i $pc => 0x80499f4 <call64_from_32+5>: push %edx (gdb) call64_from_32 () at thunks_32.S:24 24 push %esi 1: x/i $pc => 0x80499f5 <call64_from_32+6>: push %esi (gdb) call64_from_32 () at thunks_32.S:25 25 push %edi 1: x/i $pc => 0x80499f6 <call64_from_32+7>: push %edi (gdb) call64_from_32 () at thunks_32.S:28 28 jmp $0x33,$1f 1: x/i $pc => 0x80499f7 <call64_from_32+8>: ljmp $0x33,$0x80499fe (gdb) info registers eax 0x80492e8 134517480 ecx 0x3f 63 edx 0x1 1 ebx 0xf7fc8550 -134445744 esp 0xffffc57c 0xffffc57c ebp 0xffffc5e8 0xffffc5e8 esi 0x0 0 edi 0x8049180 134517120 eip 0x80499f7 0x80499f7 <call64_from_32+8> eflags 0x292 [ AF SF IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) si 32 call *%rax 1: x/i $pc => 0x80499fe <call64_from_32+15>: call *%eax (gdb) info registers eax 0x80492e8 134517480 ^^^ Should be rax ecx 0x3f 63 edx 0x1 1 ebx 0xf7fc8550 -134445744 esp 0xffffc57c 0xffffc57c ebp 0xffffc5e8 0xffffc5e8 esi 0x0 0 edi 0x8049180 134517120 eip 0x80499fe 0x80499fe <call64_from_32+15> ^^^ r8, etc are all missing eflags 0x292 [ AF SF IF ] cs 0x33 51 ^^^ 64-bit! ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) si poison_regs64 () at test_syscall_vdso.c:35 35 long syscall_addr; 1: x/i $pc => 0x80492e8 <poison_regs64>: dec %ecx (gdb) si 36 long get_syscall(char **envp) 1: x/i $pc => 0x80492ef <poison_regs64+7>: dec %ecx (gdb) set arch i386:x86-64 warning: Selected architecture i386:x86-64 is not compatible with reported target architecture i386 Architecture `i386:x86-64' not recognized. The target architecture is set to "auto" (currently "i386"). (gdb) set arch i386:x86-64:intel warning: Selected architecture i386:x86-64:intel is not compatible with reported target architecture i386 Architecture `i386:x86-64:intel' not recognized. The target architecture is set to "auto" (currently "i386"). I don't know enough about gdb internals to know precisely what failed here, but this did not work the way it should have. Sure, ptrace should provide a nice API to figure out that CS == 0x33 means long mode, but gdb could do a whole lot better here.