-
David Johnson authored
The main goal of this is QEMU support, of course. It just so happened that the best way to do it was to add a GDB stub backend (because QEMU provides a GDB stub server); and make that GDB backend capable of platform/stub-specific extensions/helper functions. So, we get QEMU support -- and we can hopefully use the GDB backend to automatically get support for other kinds of targets (like KGDB). Realistically, I implemented mostly what I needed for QEMU, so I'll probably have to beef up my support for the GDB remote protocol to truly support other target types that have a GDB stub. First, there is a GDB backend that speaks the GDB remote protocol. This is enough for it to r/w memory, most x86/x86_64 GP regs, and set/unset breakpoints and single step. Second, the GDB backend allows "helpers" to be plugged in to enhance its functionality. For instance, GDB can only read a single kind of memory; it doesn't know about virtual vs physical memory. Second, at least the part of the GDB remote protocol I implemented to read/write registers (the old bulk style, not the "new" XML style, ugh) isn't real amenable to extension... i.e., it mostly supports GP regs, not control registers or MSRs. The helper interface supports reading/writing virt/phys mem, and loading the "machine" (i.e., MSRs or other extra regs). This is necessary for QEMU, and to make the os_linux_generic OS personality able to sit atop the QEMU target (we need some control registers and an MSR). Thus, there is a "builtin" helper that speaks GDB's remote protocol to read/write memory -- and there is a QEMU helper that can load extra registers (by speaking QMP -- the QEMU monitor protocol (JSON -- ugh!)); AND can potentially read/write physical memory if QEMU is run 1) on linux with hugetlbfs and the -mem-path option, and 2) with our libqemuhacks.so library LD_PRELOADed and configured correctly! The QEMU helper is interesting. It not only reads/writes physical memory by mmap'ing the memory file QEMU created (and that libqemuhacks.so prevented QEMU from deleting, and made shareable via MAP_SHARED instead of MAP_PRIVATE); but it also sends all virtual mem reads/writes over this "channel" to physical memory. This is much, much, much faster that using GDB to read the current thread's virtual memory! Moreover, the QEMU GDB stub seems to not be able to read virtual memory chunks -- I've crashed the VM while trying -- so I only read unknown-length things like strings for which I have to scan for a '\0' using wordsize-chunk reads. The QEMU helper is helped by the libqemuhacks.so LD_PRELOADable shared lib. The way this is used is when you start QEMU, like sudo QEMU_MEMPATH_PREFIX=/hugetlbfs/qemu \ LD_PRELOAD=/opt/vmi/lib/libqemuhacks.so.0.0.0 \ qemu-system-x86_64 -cpu host -m 512 -enable-kvm \ -kernel /tftpboot/vmlinuz-2.6.18-308.el5 \ -initrd /tftpboot/automfs-2.6.18-308.el5.img \ -append console=ttyS0 -nographic -gdb tcp::1234 \ -qmp tcp:127.0.0.1:1235,server,nowait \ -mem-path /hugetlbfs libqemuhacks.so gets loaded, and it overloads unlink() and mmap() in libc. This is because when QEMU mallocs its big hunk of memory to serve as the guest's physical memory, it does so by creating a file on a hugetlbfs-backend mountpoint, backing it with a MAP_PRIVATE mmap, and immediately unlink()ing it. This prevents our backend from being able to mmap() that file and read/write physical memory directly. So -- libqemuhacks.so looks for unlink()s of any files whose pathname starts with QEMU_MEMPATH_PREFIX (in the case above, /hugetlbfs/qemu, because my hugetlbfs was mounted at /hugetlbfs, and qemu creates its RAM files starting with "qemu". After neutralizing the unlink(), libqemuhacks.so then makes sure that any mmap using an fd whose pathname starts with QEMU_MEMPATH_PREFIX is mmap'd with MAP_SHARED instead of MAP_PRIVATE. That's it -- then we can mmap it too -- without having to know about the internals of QEMU too much :). I love LD_PRELOAD; this way I didn't have to patch QEMU! (One little note is that the RAM files don't get unlink'd, so they appear in the filesystem -- BUT they don't appear to be using hugepages once QEMU closes. I can't explain this yet... but it'll be trivial to add support to store the non-unlink'd pathnames in libqemuhacks.so, and unlink them via atexit().) There were a bunch of changes necessary to handle targets that manage breakpoints and the breakpoint IP themselves, like the GDB stub does. Oh, I haven't done hardware breakpoints yet; the backend interface has to change a bit for that for the GDB backend. Also, there are still some complex multi-thread OS cases I need to port from the Xen backend into the GDB backend. The GDB protocol is ugly. I'm just going to leave it at that.
361cf775