Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Debug NetworkManager with GDB

+4
−0

I'd like to debug NetworkManager by stepping through it using GDB. I assume I'll have to compile NetworkManager from source to get debug symbols since file /usr/bin/NetworkManager indicates that the binary is stripped, having no debug symbols.

I'm on Arch Linux and I can see that systemd starts NetworkManager. Preferably, I'd be able to debug a NetworkManager process started by systemd.

History
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

1 answer

+4
−0

Note that if you want to debug the currently installed version of NetworkManager, you don't have to compile NetworkManager yourself. Instead, make GDB download symbol files via debuginfod. You can skip to section "Debug NetworkManager with GDB" of this answer to see how.

Clone, configure, and compile

If you still want to compile NetworkManager yourself (e.g., to edit its code), here are the steps.

Clone NetworkManager's repository:

git clone https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git --depth 1

Before configuring (with autogen.sh) and compiling, make sure you have the required packages installed. I was missing gtk-doc, gobject-introspection, and ppp which caused errors:

./autogen.sh: line 25: gtkdocize: command not found

configure: error: introspection enabled but can't be used

configure: error: "couldn't find pppd.h. pppd development headers are required."

You'll probably need base-devel installed as well:

sudo pacman -S base-devel gtk-doc gobject-introspection ppp

Although NetworkManager will run with root privileges, it needs to be installed in a path entirely owned by root. If you put your self-compiled NetworkManager in a directory like /home/me/nm_install_dir, even if you chown root:root /home/me/nm_install_dir/, it will start but won't assign IP addresses and will print errors like these:

Cannot create parents for '/home/me/nm_install_dir/var/lib/NetworkManager': Read-only file system

secret-key: failure to persist secret key in "/home/me/nm_install_dir/var/lib/NetworkManager/secret_key" (failed to create file /home/me/nm_install_dir/var/lib/NetworkManager/secret_key.KG6J61: Read-only file system) (use non-persistent key)

config: device-state: write #3 (/home/me/nm_install_dir/var/run/NetworkManager/devices/3) failed: Failed to create file “/home/me/nm_install_dir/var/run/NetworkManager/devices/3.C2ZI61”: Read-only file system

Thus, I used a directory in the root directory for putting NetworkManager's binary, configuration, and runtime files:

./autogen.sh --prefix=/nm_install_dir

Then, compile and install NetworkManager with:

make -j 8 && sudo make install

If you encounter issues while configuring or compiling, see NetworkManager's CONTRIBUTING.md which also links to required packages.

Increase logging

It can be useful to have NetworkManager produce more detailed log messages; create a file /nm_install_dir/etc/NetworkManager/NetworkManager.conf containing this:

[logging]
domains=ALL:TRACE

Run self-compiled NetworkManager

Stop your currently running instance of NetworkManager with systemctl stop NetworkManager and (optionally) remove current IP addresses from your interfaces with ip addr flush up.

On Arch Linux, systemd starts NetworkManager as defined in the unit file /usr/lib/systemd/system/NetworkManager.service. In that file, I changed the line

ExecStart=/usr/bin/NetworkManager --no-daemon

to

ExecStart=/nm_install_dir/sbin/NetworkManager --no-daemon

and ran systemctl daemon-reload && systemctl start NetworkManager.

There are other ways to do that, as described here.

Make sure you're indeed running the self-compiled version of NetworkManager with systemctl status NetworkManager. Check the logs with journalctl --since=-5m -u NetworkManager to see if there are any warnings or errors.

Debug NetworkManager with GDB

If you want to debug NetworkManager without it being started by systemd, run this as root:

# Stop the systemd-started NetworkManager
systemctl stop NetworkManager
# Change NetworkManager's executable path if you didn't compile it yourself
DEBUGINFOD_URLS="https://debuginfod.archlinux.org/" gdb /nm_install_dir/sbin/NetworkManager

The environment variable DEBUGINFOD_URLS enables GDB to download debugging symbols on demand using debuginfod. We set the variable here explicitly since per default, user root doesn't have that variable set.

Whether or not you have compiled NetworkManager yourself, you probably still want to have debuginfod activated since it also fetches the debugging symbols of NetworkManager's dependencies (like libglib and libgobject) which you don't get when compiling NetworkManager.

Start NetworkManager with systemd and debug with GDB

Alternatively, we can attach GDB to the NetworkManager process once systemd has started it. Prerequisite for this is GDB having the capability to attach to a running process, discussed here:

sudo setcap CAP_SYS_PTRACE=+eip /usr/bin/gdb

Make sure NetworkManager is not running with systemctl stop NetworkManager.

Save the following script, adapted from here, as gdbwait:

#!/bin/sh
process_name="$1"
breakpoint_location="$2"
echo "Waiting for $process_name to start"
pid=$(pgrep -o "$process_name")
while [ "$pid" = "" ]; do
  pid=$(pgrep -o "$process_name")
done

# Per default, user root doesn't have the environment variable DEBUGINFOD_URLS → Set it to download symbols as needed
DEBUGINFOD_URLS="https://debuginfod.archlinux.org/" gdb -ex "break $breakpoint_location" -ex continue -p "$pid"

To avoid GDB's prompt "Enable debuginfod for this session?", you can echo "set debuginfod enabled on" >> /root/.gdbinit.

Then, run ./gdbwait NetworkManager yourDebugLocation as root and systemctl start NetworkManager afterwards. GDB needs root privileges, otherwise GDB won't be able to debug the process and will print errors:

warning: "target:/nm_install_dir/sbin/NetworkManager": could not open as an executable file: Operation not permitted.

warning: `target:/nm_install_dir/sbin/NetworkManager': can't open to read symbols: Operation not permitted.

warning: opening /proc/self/mem file failed: Permission denied (13)

Mind that gdbwait won't be able to break at early functions like main since detecting the process and attaching to it takes longer than for main to have started.

But this for example should work (using TUI here):

./gdbwait NetworkManager nm_utils_ipv6_addr_set_stable_privacy_with_host_id

screenshot of debugging NetworkManager in GDB with TUI

History
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comment threads

Sign up to answer this question »