[PATCHv6 7/9] gdb/gdbserver: share some code relating to target description creation
John Baldwin
jhb@FreeBSD.org
Wed May 8 22:58:05 GMT 2024
On 5/8/24 9:46 AM, Andrew Burgess wrote:
> This commit is part of a series to share more of the x86 target
> description creation code between GDB and gdbserver.
>
> Unlike previous commits which were mostly refactoring, this commit is
> the first that makes a real change, though that change should mostly
> be for gdbserver; I've largely adopted the "GDB" way of doing things
> for gdbserver, and this fixes a real gdbserver bug.
>
> On a x86-64 Linux target, running the test:
>
> gdb.server/connect-with-no-symbol-file.exp
>
> results in two core files being created. Both of these core files are
> from the inferior process, created after gdbserver has detached.
>
> In this test a gdbserver process is started and then, after gdbserver
> has started, but before GDB attaches, we either delete the inferior
> executable, or change its permissions so it can't be read. Only after
> doing this do we attempt to connect with GDB.
>
> As GDB connects to gdbserver, gdbserver attempts to figure out the
> target description so that it can send the description to GDB, this
> involves a call to x86_linux_read_description.
>
> In x86_linux_read_description one of the first things we do is try to
> figure out if the process is 32-bit or 64-bit. To do this we look up
> the executable via the thread-id, and then attempt to read the
> architecture size from the executable. This isn't going to work if
> the executable has been deleted, or is no longer readable.
>
> And so, as we can't read the executable, we default to an i386 target
> and use an i386 target description.
>
> A consequence of using an i386 target description is that addresses
> are assumed to be 32-bits. Here's an example session that shows the
> problems this causes. This is run on an x86-64 machine, and the test
> binary (xx.x) is a standard 64-bit x86-64 binary:
>
> shell_1$ gdbserver --once localhost :54321 /tmp/xx.x
>
> shell_2$ gdb -q
> (gdb) set sysroot
> (gdb) shell chmod 000 /tmp/xx.x
> (gdb) target remote :54321
> Remote debugging using :54321
> warning: /tmp/xx.x: Permission denied.
> 0xf7fd3110 in ?? ()
> (gdb) show architecture
> The target architecture is set to "auto" (currently "i386").
> (gdb) p/x $pc
> $1 = 0xf7fd3110
> (gdb) info proc mappings
> process 2412639
> Mapped address spaces:
>
> Start Addr End Addr Size Offset Perms objfile
> 0x400000 0x401000 0x1000 0x0 r--p /tmp/xx.x
> 0x401000 0x402000 0x1000 0x1000 r-xp /tmp/xx.x
> 0x402000 0x403000 0x1000 0x2000 r--p /tmp/xx.x
> 0x403000 0x405000 0x2000 0x2000 rw-p /tmp/xx.x
> 0xf7fcb000 0xf7fcf000 0x4000 0x0 r--p [vvar]
> 0xf7fcf000 0xf7fd1000 0x2000 0x0 r-xp [vdso]
> 0xf7fd1000 0xf7fd3000 0x2000 0x0 r--p /usr/lib64/ld-2.30.so
> 0xf7fd3000 0xf7ff3000 0x20000 0x2000 r-xp /usr/lib64/ld-2.30.so
> 0xf7ff3000 0xf7ffb000 0x8000 0x22000 r--p /usr/lib64/ld-2.30.so
> 0xf7ffc000 0xf7ffe000 0x2000 0x2a000 rw-p /usr/lib64/ld-2.30.so
> 0xf7ffe000 0xf7fff000 0x1000 0x0 rw-p
> 0xfffda000 0xfffff000 0x25000 0x0 rw-p [stack]
> 0xff600000 0xff601000 0x1000 0x0 r-xp [vsyscall]
> (gdb) info inferiors
> Num Description Connection Executable
> * 1 process 2412639 1 (remote :54321)
> (gdb) shell cat /proc/2412639/maps
> 00400000-00401000 r--p 00000000 fd:03 45907133 /tmp/xx.x
> 00401000-00402000 r-xp 00001000 fd:03 45907133 /tmp/xx.x
> 00402000-00403000 r--p 00002000 fd:03 45907133 /tmp/xx.x
> 00403000-00405000 rw-p 00002000 fd:03 45907133 /tmp/xx.x
> 7ffff7fcb000-7ffff7fcf000 r--p 00000000 00:00 0 [vvar]
> 7ffff7fcf000-7ffff7fd1000 r-xp 00000000 00:00 0 [vdso]
> 7ffff7fd1000-7ffff7fd3000 r--p 00000000 fd:00 143904 /usr/lib64/ld-2.30.so
> 7ffff7fd3000-7ffff7ff3000 r-xp 00002000 fd:00 143904 /usr/lib64/ld-2.30.so
> 7ffff7ff3000-7ffff7ffb000 r--p 00022000 fd:00 143904 /usr/lib64/ld-2.30.so
> 7ffff7ffc000-7ffff7ffe000 rw-p 0002a000 fd:00 143904 /usr/lib64/ld-2.30.so
> 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
> 7ffffffda000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
> ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
> (gdb)
>
> Notice the difference between the mappings reported via GDB and those
> reported directly from the kernel via /proc/PID/maps, the addresses of
> every mapping is clamped to 32-bits for GDB, while the kernel reports
> real 64-bit addresses.
>
> Notice also that the $pc value is a 32-bit value. It appears to be
> within one of the mappings reported by GDB, but is outside any of the
> mappings reported from the kernel.
>
> And this is where the problem arises. When gdbserver detaches from
> the inferior we pass the inferior the address from which it should
> resume. Due to the 32/64 bit confusion we tell the inferior to resume
> from the 32-bit $pc value, which is not within any valid mapping, and
> so, as soon as the inferior resumes, it segfaults.
>
> If we look at how GDB (not gdbserver) figures out its target
> description then we see an interesting difference. GDB doesn't try to
> read the executable. Instead GDB uses ptrace to query the thread's
> state, and uses this to figure out the if the thread is 32 or 64 bit.
>
> If we update gdbserver to do it the "GDB" way then the above problem
> is resolved, gdbserver now sees the process as 64-bit, and when we
> detach from the inferior we give it the correct 64-bit address, and
> the inferior no longer segfaults.
>
> Now, I could just update the gdbserver code, but better, I think, to
> share one copy of the code between GDB and gdbserver in gdb/nat/.
> That is what this commit does.
>
> The cores of x86_linux_read_description from gdbserver and
> x86_linux_nat_target::read_description from GDB are moved into a new
> file gdb/nat/x86-linux-tdesc.c and combined into a single function
> x86_linux_tdesc_for_tid which is called from each location.
>
> This new function does things mostly the GDB way, some changes are
> needed to allow for the sharing; we now take some pointers for where
> the shared code can cache the xcr0 and xsave layout values.
>
> Another thing to note about this commit is how the functions
> i386_linux_read_description and amd64_linux_read_description are
> handled. For now I've left these function as implemented separately
> in GDB and gdbserver. I've moved the declarations of these functions
> into gdb/arch/{i386,amd64}-linux-tdesc.h, but the implementations are
> left where they are.
>
> A later commit in this series will make these functions shared too,
> but doing this is not trivial, so I've left that for a separate
> commit. Merging the declarations as I've done here ensures that
> everyone implements the function to the same API, and once these
> functions are shared (in a later commit) we'll want a shared
> declaration anyway.
>
> Reviewed-By: Felix Willgerodt <felix.willgerodt@intel.com>
Acked-By: John Baldwin <jhb@FreeBSD.org>
--
John Baldwin
More information about the Gdb-patches
mailing list