Getting the GNU gdbserver to work

August 12, 2019 posted by Kamil Rytarowski

A number of the remaining reported ptrace(2) bugs are GDB related. The previous support for GDB in NetBSD was in need for refreshment, as it had no support for gdbserver capabilities. The GDB Server is an execution mode of the debugger, which spawns a dedicated process that interacts with its tracee. The process then establishes a link (socket, serial, ...) with the GDB client that is controlled by a programmer.

As NetBSD-9 has finally branched and I keep receiving requests to finish the integration of LLVM sanitizers, I have pushed this task forward too. I have also completed a few leftover tasks from my previous months that still needed fixes.


Originally the GDB debugger was meant for local debugging. However with the request of tracing remote setups, it has been extended to remote debugging capabilities and this move standardized the protocol for many debuggers.

In fact the native / local / non-remote debugging is redundant with the remote capabilities, however this blog entry is not the right place to discuss the technical merits in comparision between them trying to convince someone. What matters: the developers of LLDB (LLVM debugger) already removed their local debugging variation (for Linux) and implements only the remote process plugin. The NetBSD support for LLDB started with this mode of copying the Linux approach. Bypassing no longer exists for Linux local-debugging-only support plugin.

Inside the GNU world, the transition from local process debugging to remote process debugging is progressing slowly. In the current state of affairs there is a need to support two separate (however whenever possible, with code sharing) plugins for each OS. Also, there is intention from some GNU debugger developers to completely drop the native-only process plugin to debugging code. The state in NetBSD one month ago handled only local-debugging and no code for remote process debugging. The state is the same with other BSD derived systems (FreeBSD, DragonFlyBSD...) and this state was in general kept alive with a reduced set of features compared to Linux.

I have decided to refresh the GDB support for NetBSD as this is still the primary debugger on NetBSD (LLDB support is still work-in-progress) for two primary reasons:

  • Slight ptrace(2) changes in the kernel code can alter support in GDB/NetBSD. With proper NetBSD handling in GDB and ability to run its regression tests the fallout will be minimized.
  • Certain ptrace(2) reported bugs are in fact specific GDB bugs. In order to close them as resolved I need to revamp and validate the GDB support.

I have managed to get a basic GDB client/server session to work for tracing a simple application. The following features have been implemented targetting as of now NetBSD/amd64:

  • creating inferior (debuggee in GDB terminology)
  • attaching
  • killing
  • detaching
  • resuming (with optional: single step, signal, resuming single thread)
  • waiting
  • checking whether a thread is alive
  • fetching registers
  • storing registers
  • reading memory
  • writing memory
  • requesting interruption
  • auxv reading
  • software breakpoint support
  • hardware single step support
  • svr4 ELF loader tracing
  • retrieving exec file name from pid
  • reading thread name
What is still missing in gdbserver for NetBSD/amd64:
  • i386 support
  • multilib support amd64/i386
  • reading TLS BASE (x86) register (there is still missing a ptrace(2) interface)
  • EXEC events handling improvement in the generic code (that maps Linux restricted semantics only)
  • hardware watchpoint/breakpoint support
  • FPU support
  • reading loadmap
  • research for other features: multiprocess, mulifs, async, btrace, tracepoints, new gdb connections..

The main difficulty was with overly elaborated version of Linux proccess tracing in GDB that contains various workaround for various kernel bugs, handles differences between behavior of the Linux kernel (like different set of ptrace(2) calls or.. swapped arguments) between CPUs.. Finally, I have decided to base my work on unfortunately dated (and probably broken today) gdbserver for lynxos/i386 and then keep adding missing features that are implemented for Linux. I have passed most of the past month on debugging spurious crashes and anomalies in my GDB remote port to NetBSD. After much work, I have finally managed to get gdbserver to work and perform successful operations of spawning a process, inserting a breakpoint, single-stepping, detaching and running a process until its natural completion.

I plan to validate the native tracing support for NetBSD, checking whether it needs upgrading and planning to run the GDB regression tests as soon as possible.

LLVM changes

I have updated the list of ioctl(2) operations to the state as of 9.99.3 (+36 ioctls). The support for NVMM ioctl(2)s has been enabled and restricted as of now to amd64 only.

I have also finally managed to resolve the crash of dynamic (as DSO library) Address Sanitizer that blocked the integration with base in Januray 2019. My original suspect on the root cause was finally verified to be false (mismatch in the source code files composing .so libraries). The real reason to ship with broken dynamic ASan was inability to reuse the same implementation of TSD (Thread-Specific Data) in asan-dynamic. The static (default in LLVM) version of ASan can use in early initialization TLS (Thread-Local Storage), while TSD (Thread-Specific Data) is broken. It happened that the state with dynamic ASan is inversed and TLS breaks and TSD works.

I have also landed build rules for LLVM sanitizers into src/, for:

  • asan
  • ubsan
  • tsan
  • msan
  • xray
  • safestack
  • libfuzzer
These features are targetting in all the supported variations NetBSD/amd64. The build rules are still not hooked into the MKLLVM=yes build as I intend to backport the needed patches to llvm-8 enhancements from llvm-HEAD and then reimport that snapshot into the NetBSD's distribution, avoiding downstream patches.

MAXRSS changes

During the work on libfuzzer last year for GSoC-2018 one of the changes that landed the kernel was the restoration of the MAXRSS option. MAXRSS presents the maxiumum resident set size of the process during its lifetime. In order to finalize this work, there was still need to enable printing it in ps(1). I have pushed a kernel fix to update the RSS related values for sysctl(3) query of a process statistics and with help of Krzysztof Lasocki reenabled printing MAXRSS, IDRSS (integral unshared data), ISRSS (integral unshared stack) and IXRSS (integral shared memory size) in ps(1). These values were commented out in the ps(1) program since the inception of NetBSD, the first registered commit.

$ ps -O maxrss,idrss,isrss,ixrss|head -3
 910   5844    20    12   216 pts/0  Is   0:00.01 -ksh
1141   5844    20    12   152 pts/0  I+   0:00.01 mg event.h

These change have been backported to the NetBSD-9 branch and will land 9.0. Welcome back!

Plan for the next milestone

Start executing GDB regression tests. Keep enhancing GDB support. Keep detecting ptrace(2) bugs and addressing them.

This work was sponsored by The NetBSD Foundation.

The NetBSD Foundation is a non-profit organization and welcomes any donations to help us continue funding projects and services to the open-source community. Please consider visiting the following URL to chip in what you can: [0 comments]


Post a Comment:
  • HTML Syntax: NOT allowed