Cannot set kernel dynamic debug on Linux? - linux

I have already seen Cannot enable kernel dynamic debugging on linux ; https://www.kernel.org/doc/html/v4.11/admin-guide/dynamic-debug-howto.html .
I have rebuilt the Raspbian 9 kernel with CONFIG_DYNAMIC_DEBUG, and booted into it; the file /sys/kernel/debug/dynamic_debug/control and is populated with 2k+ dynamic debug rule statements:
pi#raspberrypi:~ $ sudo ls -la /sys/kernel/debug/dynamic_debug/control
-rw-r--r-- 1 root root 0 Jan 1 1970 /sys/kernel/debug/dynamic_debug/control
pi#raspberrypi:~ $ sudo cat /sys/kernel/debug/dynamic_debug/control | wc -l
2358
pi#raspberrypi:~ $ sudo grep 'snd_device' /sys/kernel/debug/dynamic_debug/control
sound/core/device.c:132 [snd]snd_device_disconnect =_ "device disconnect %p (from %pS), not found\012"
sound/core/device.c:156 [snd]snd_device_free =_ "device free %p (from %pS), not found\012"
Ok, so I want to trace the is_connected_output_ep function, which is in sound/soc/soc-dapm.c. So I do this:
pi#raspberrypi:~ $ sudo bash -c "echo -n 'func is_connected_output_ep +p' > /sys/kernel/debug/dynamic_debug/control"
pi#raspberrypi:~ $ sudo cat /sys/kernel/debug/dynamic_debug/control | grep is_conn
pi#raspberrypi:~ $
pi#raspberrypi:~ $ sudo bash -c "echo 'file sound/soc/soc-dapm.c line 1175 +p' > /sys/kernel/debug/dynamic_debug/control"
pi#raspberrypi:~ $ sudo cat /sys/kernel/debug/dynamic_debug/control | grep dapm
pi#raspberrypi:~ $
... and I get no errors - but seemingly, nothing "sticks". (and yeah, I don't see this function being traced either).
The documentation says that +p does:
p enables the pr_debug() callsite.
I'm not sure what they mean by this - does it mean that if there are already existing pr_debug statements in the function, then they will be enabled (i.e. will print to syslog) with this? If so, what happens in the case when there are no such statements in the function - as is the case with is_connected_output_ep? Can I still setup dynamic debug to somehow trace this function - without having to manually insert printk or other statements and recompiling the kernel module?

Well, I did some more reading, and it seems the answer to:
does it mean that if there are already existing pr_debug statements in the function, then they will be enabled (i.e. will print to syslog) with this?
... is likely "yes" - so you cannot do dynamic debug of a function that does not have pr_debug statements in it already.
Also, it seems that the /sys/kernel/debug/dynamic_debug/control (upon read) is actually a list of all possible dynamic debug "probe points" if you will, along with their status (enabled or not), though I'm not sure about this.
Anyways, here is some more reading where this stuff is mentioned:
The dynamic debugging interface [LWN.net] 2011
Dynamic Debug, conference paper, 2009
So I cannot trace is_connected_output_ep with dynamic debug - so maybe I should look into ftrace or kprobes (dynamic probes) facilities of the Linux kernel...
EDIT: It turns out, dynamic_debug/control lists debuggable statements ONLY from currently loaded modules in the kernel! Example, there is a dev_dbg in the dpcm_path_get function in the soc-pcm.c source file, which ends up in the snd_soc_core kernel module (snd-soc-core.ko). This module by default is not loaded by Raspbian 9, so we get this:
pi#raspberrypi:~ $ lsmod | grep snd
snd_bcm2835 32768 1
snd_pcm 98304 1 snd_bcm2835
snd_timer 32768 1 snd_pcm
snd 69632 5 snd_timer,snd_bcm2835,snd_pcm
pi#raspberrypi:~ $ sudo grep 'soc-pcm' /sys/kernel/debug/dynamic_debug/control
pi#raspberrypi:~ $
Ok, now if the kernel module is loaded with modprobe, now suddenly the debuggable callsites appear in dynamic_debug/control:
pi#raspberrypi:~ $ sudo modprobe snd_soc_core
pi#raspberrypi:~ $ lsmod | grep snd
snd_soc_core 200704 0
snd_compress 20480 1 snd_soc_core
snd_pcm_dmaengine 16384 1 snd_soc_core
snd_bcm2835 32768 1
snd_pcm 98304 3 snd_pcm_dmaengine,snd_bcm2835,snd_soc_core
snd_timer 32768 1 snd_pcm
snd 69632 7 snd_compress,snd_timer,snd_bcm2835,snd_soc_core,snd_pcm
pi#raspberrypi:~ $ sudo grep 'soc-pcm' /sys/kernel/debug/dynamic_debug/control
sound/soc/soc-pcm.c:1367 [snd_soc_core]dpcm_prune_paths =_ "ASoC: pruning %s BE %s for %s\012"
sound/soc/soc-pcm.c:1373 [snd_soc_core]dpcm_prune_paths =_ "ASoC: found %d old BE paths for pruning\012"
...
pi#raspberrypi:~ $ sudo grep 'dpcm_path_get' /sys/kernel/debug/dynamic_debug/control
sound/soc/soc-pcm.c:1331 [snd_soc_core]dpcm_path_get =_ "ASoC: found %d audio %s paths\012"
And finally, we can now enable this print statement:
pi#raspberrypi:~ $ sudo bash -c "echo 'func dpcm_path_get +p' > /sys/kernel/debug/dynamic_debug/control"
pi#raspberrypi:~ $ sudo grep 'dpcm_path_get' /sys/kernel/debug/dynamic_debug/control
sound/soc/soc-pcm.c:1331 [snd_soc_core]dpcm_path_get =p "ASoC: found %d audio %s paths\012"
Apparently, the disabled lines have a =_ symbol in the line, and the enabled lines have =p ...
Now all that I'd want, is to enable some statements before the driver is loaded, so I could monitor printouts in _probe functions of kernel module drivers...

You can add following argument to insmod
dyndbg="+p"

Related

How to configure Ftrace on kernel 5.15.0-56-generic (ubuntu 22.04)?

I'm trying to configure and enable ftrace on my ubuntu machine but its doesn't work. I also tried the instructions from the link here. I'm sure I'm missing something minor but I can't tell what.
Configuration:
$ cat /boot/config-5.15.0-56-generic | grep CONFIG_FUNCTION_TRACER
CONFIG_FUNCTION_TRACER=y
$ cat /boot/config-5.15.0-56-generic | grep CONFIG_FUNCTION_GRAPH_TRACER
CONFIG_FUNCTION_GRAPH_TRACER=y
$ cat /boot/config-5.15.0-56-generic | grep CONFIG_STACK_TRACER
CONFIG_STACK_TRACER=y
$ cat /boot/config-5.15.0-56-generic | grep CONFIG_DYNAMIC_FTRACE
CONFIG_DYNAMIC_FTRACE=y
$ uname -a
Linux <redacted> 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Enable tracing (with root user)
$ echo function > /sys/kernel/debug/tracing/current_trace
$ echo do_sys_open > /sys/kernel/debug/tracing/set_ftrace_filter
$ echo 1 > tracing_on
debugfs is already mounted:
$ mount
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
tracefs on /sys/kernel/debug/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
After enabling the tracing I was expecting to see the traces in /sys/kernel/debug/tracing/trace or /sys/kernel/debug/tracing/trace_pipe files but I didn't see any traces.
Update: Instructions to generate the traces are working as expected. I was able to generate the traces successfully for do_sys_openat2 but with do_sys_open I don't see any traces.

Suspend / Hibernate cannot resume laptop

I'm trying to configure Suspend/Hibernate with my laptop and I issued some troubles.
I noticed the following troubles:
Suspend :
- Switching the lid off of my laptop : When I switch the lid on of the laptop, nothing happens. I must push down the power button to force the shutdown and then switch on the laptop.
- Typing systemctl suspend : same as previously.
Hibernate :
- Typing systemctl hibernate : the laptop seems to shutdown
I read those following links for helping me :
Hibernate with swap file
Suspend and hibernate
My system :
4.13.0-38-generic #43-Ubuntu SMP Wed Mar 14 15:20:44 UTC 2018 x86_64 GNU/Linux
My swap :
$ cat /etc/fstab
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=403661c1-c7b4-47a8-9493-c5c0262ce14e / ext4 errors=remount-ro 0 1
UUID=BF40-CD4F /boot/efi vfat umask=0077 0 1
/swapfile none swap sw 0 0
/swap swap swap defaults 0 0
What I've done :
Create swap file
$ fallocate -l 8g /swap
$ mkswap /swap
Add swappiness
sysctl -w vm.swappiness=1
$ cat /etc/sysctl.conf | grep swappiness
vm.swappiness=1
$ swapon /swap
Configure grub
$ cat /etc/default/grub | grep -i grub_cmdline_linux_default
GRUB_CMDLINE_LINUX_DEFAULT="resume=/swap resume_offset=60354560 quiet splash"
$ sudo filefrag -v /swap | head -n4
Filesystem type is: ef53
File size of /swap is 8589934592 (2097152 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 0: 60354560.. 60354560: 1:
According to previous links I could configure /etc/mkinitcpio.conf but there is no file like this in my system.
So, I don't really know how to configure my initramfs.
Here is my configuration from /sys/power :
$ cat /sys/power/disk
[platform] shutdown reboot suspend test_resume
$ cat /sys/power/mem_sleep
s2idle [deep]
$ cat /sys/power/image_size
3261943808
$ cat /sys/power/resume
0:0
Could you give me some hints to make a step forward. Thanks you.

how to check if Linux symlink is in use? (removing unused symlink)

fuser can show you ONLY if original file is in use.
fuser DOESN'T SHOW YOU IF SYMLINK IS IN USE which calls original file. That's the issue. You don't know if symlink unused and can be removed.
I have started two processes (24261 opened original file and 24262 opened symlink) :
root#server DEV # ls -l /lib64/libgcc_s-4.4.7-20120601.so.1
-rwxr-xr-x 1 root root 93320 Sep 1 2014 /lib64/libgcc_s-4.4.7-20120601.so.1
root#server DEV # ls -l /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
lrwxrwxrwx. 1 root root 20 Oct 19 2015 /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so -> /lib64/libgcc_s.so.1
root#server DEV #
root#server DEV # tail -f /lib64/libgcc_s.so.1 &
[1] 24261
root#server DEV #
root#server DEV # cd /usr/lib/gcc/x86_64-redhat-linux/4.4.4
root#server DEV # tail -f libgcc_s.so &
[2] 24262
root#server DEV #
root#server DEV # ps -ef | grep tail
root 24261 3265 0 13:39 pts/1 00:00:00 tail -f /lib64/libgcc_s.so.1
root 24262 3265 0 13:39 pts/1 00:00:00 tail -f libgcc_s.so
root 24492 3265 0 13:40 pts/1 00:00:00 grep tail
root#server DEV #
In both cases fuser tells that symlink and original file is in use (there are two processes for each command):
root#server DEV # fuser /lib64/libgcc_s.so.1
/lib64/libgcc_s.so.1: 24261 24262
root#server DEV # fuser /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so: 24261 24262
root#server DEV #
But we know that symlink was not used for the first process. It can be even removed and will not affect first process.
Let's say I want to remove 'gcc' package if the package is not in use.
Original file comes from 'libgcc' package.
root#server DEV # rpm -qf /lib64/libgcc_s.so.1
libgcc-4.4.7-11.el6.x86_64
Symlink comes from 'gcc' package:
root#server DEV # rpm -qf /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
gcc-4.4.7-11.el6.x86_64
If I will remove 'gcc' package which contains only symlink, I will affect second process! How I can see if symlink is unused?
In my case 'ps -ef' shows that I used command:
root 24262 3265 0 13:39 pts/1 00:00:00 tail -f libgcc_s.so
So ps cannot even tell you that symlink was used.
Any Linux guru?
EDITED:
There is partial solution checking cwd - current working directory:
root#server DEV # ls -l /proc/24262/cwd
lrwxrwxrwx 1 root root 0 Jun 20 13:57 /proc/24262/cwd -> /usr/lib/gcc/x86_64-redhat-linux/4.4.4
root#server DEV #
So from here you see the path "/usr/lib/gcc/x86_64-redhat-linux/4.4.4" and you can get file name from ps.
This doesn't work if you do:
root#server DEV # cd /root
root#server DEV # cat script.sh
/usr/bin/tail -f /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
root#server DEV #
root#server DEV # nohup ./script.sh &
[2] 26713
root#server DEV #
root#server DEV # ls -l /proc/26713/cwd
lrwxrwxrwx 1 root root 0 Jun 20 14:32 /proc/26713/cwd -> /root
It shows cwd for /root, but symlink is inside the script/program. So then you need to check ps chill process for /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so.
root#server DEV # ps -ef | grep 26713
root 26713 3265 0 14:32 pts/1 00:00:00 /bin/sh ./script.sh
root 26714 26713 0 14:32 pts/1 00:00:00 /usr/bin/tail -f /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc_s.so
root 26780 3265 0 14:38 pts/1 00:00:00 grep 26713
root#server DEV #
This is very confusing when you want to automate package removal (if the package is not in use).
It will be great if someone can see simpler way of this. Also if someone can confirm the accuracy of using cwd and ps child processes for symlink in use detection.
What will happen if script.sh would be binary file? Will I still able to see full symlink path in 'ps' or cwd?
Symlinks are not usual files: they cannot be opened with open() like regular files or directories. Symlink actually is just a constant string, which is automatically interpreted internally during path resolution.
Because of that symlinks are not "used" in the sence of utilities like fuser. When you call fuser for symlink, it actually shows info about file pointed by the link.
If by "in use" you mean "one or more programs is using the link as its path name for the file", then there is no way to tell. It could have been used yesterday, and it might be used tomorrow. Unix is designed so that, unless you are specifically using tools designed for that specific purpose, a symlink looks just like the file it points to. Programs like fuser or lsof will just go right through the links without even telling you it's a link.
If by "in use" you mean "points to a valid file", then there are ways to tell. The simplest being ls -L
$ ls -l foo
/bin/ls: cannot access foo: No such file or directory
$ ls -l g
lrwxrwxrwx 1 hymie users 3 2016-06-20 10:09 g -> foo
$ ls -lL g
/bin/ls: cannot access g: No such file or directory
Unfortunately, Linux kernel is designed to assign original file from the symlink in the start up phase. So when the process is running there is no possibility to check if file called directly or through symlink.
All you can do is to check what was current working directory ls -l /proc/<process_id>/cwd, command line arguments strings /proc/<process_id>/cmdline, what user started the process ps -ef | grep <process_id> then you can check user startup scripts and $PATH, ldd can show you which libraries are called from particular library. If you want to restart the process to see if symlink called then strace is your friend.
The premise of this question (identifying unused packages with fuser / lsof) is fundamentally flawed:
Not every file your system needs to work properly will referenced by an open file descriptor at any random time.
For example, you would have a bad time if you removed /bin/systemctl (since things like /sbin/shutdown are symlinks to it), but lsof shows nothing using it.
It's easy to come up with many more examples, like /bin/grep on my system. It's used all over the place in shell scripts, but I don't happen to have any long-running instances of it.

QEMU: /bin/sh: can't access tty; job control turned off

As a development environment for linux kernel, I'm using qemu with setting up initramfs as similar to what is shown here, with few additional executable. Basically, it uses busybox for creating minimal environment and package it up using cpio. Content of init is shown below.
$ cat init
mount -t proc none /proc
mount -t sysfs none /sys
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
exec /bin/sh
Using following command to start VM:
qemu-system-x86_64 -kernel bzImage -initrd initramfs -append "console=ttyS0" -nographic
It throws following error:
/bin/sh: can't access tty; job control turned off
Although, system functions normal in most cases. But, I'm not able to create background process:
$ prog &
/bin/sh: can't open '/dev/null'
$ fg
/bin/sh: fg: job (null) not created under job control
Root of all problems seem to be not having access to tty. How can I fix this?
EDIT: Apart from Accepted answer, as a get around cttyhack of busybox can be used.
$cat init
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mknod -m 666 /dev/ttyS0 c 4 64
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack sh
exec /bin/sh
From Linux From Scratch Chapter 6.8. Populating /dev
6.8.1. Creating Initial Device Nodes
When the kernel boots the system, it requires the presence of a few device nodes, in particular the console and null devices. Create these by running the following commands:
mknod -m 600 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
You should then continue with the steps in "6.8.2. Mounting tmpfs and Populating /dev". Note the <-- below, and I suggest you read the entire free LFS.
mount -n -t tmpfs none /dev
mknod -m 622 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/zero c 1 5
mknod -m 666 /dev/ptmx c 5 2
mknod -m 666 /dev/tty c 5 0 # <--
mknod -m 444 /dev/random c 1 8
mknod -m 444 /dev/urandom c 1 9
chown root:tty /dev/{console,ptmx,tty}

Find pci of hostbridge of a device in FreeBSD10

I have a pci address for a device, and need to find the pci address of its hostbridge. In FreeBSD 11 it is very easy to do that using "devinfo -v" as you can grep the pci address of the device and then you can find its parent in the tree which is the hostbridge. Now in FreeBSD 10 there is no any pci address in the output of the "devinfo -v". Example of "devinfo -v" output in FreeBSD 11:
pcib4 pnpinfo vendor=0x8086 device=0x2f08 subvendor=0x15d9 subdevice=0x0833 class=0x060400 at pci0:0:3:0 handle=\_SB_.PCI0.BR3A
pci4
mlx5_core1 pnpinfo vendor=0x15b3 device=0x1013 subvendor=0x15b3 subdevice=0x0010 class=0x020700 at pci0:3:0:0 handle=\_SB_.PCI0.BR3A.H000
mlx5_core2 pnpinfo vendor=0x15b3 device=0x1013 subvendor=0x15b3 subdevice=0x0010 class=0x020700 at pci0:3:0:1 handle=\_SB_.PCI0.BR3A.H001
Example of "devinfo -v" output in FreeBSD 10:
pcib4 pnpinfo vendor=0x8086 device=0x2f08 subvendor=0x15d9 subdevice=0x0833 class=0x060400
pci4
mlx5_core1 pnpinfo vendor=0x15b3 device=0x1013 subvendor=0x15b3 subdevice=0x0010 class=0x020700
mlx5_core2 pnpinfo vendor=0x15b3 device=0x1013 subvendor=0x15b3 subdevice=0x0010 class=0x020700
So You can see that the pci addresses are not appearing in output of FreeBSD10
There is 2-step workaround. At first find device name:
pciconf -l -v | grep "pci0:2:0:0" | cut -f 1 -d #
In my case it's sdhci_pci0.
Then find location in devinfo:
$ devinfo | grep -B 5 sdhci_pci0
pcm2
pcm3
pcm4
pcib1
pci2
sdhci_pci0
Note:
On FreeBSD10.2-STABLE I can see PCI info in output of devinfo.
Another possibility is to walk through the dev sysctl tree:
You can grep for the PCI address you have in the %location OID:
$ sysctl dev | grep %location
dev.hdac.1.%location: pci0:0:27:0 handle=\_SB_.PCI0.HDEF
dev.hdac.0.%location: pci0:2:0:1
dev.vgapci.0.%location: pci0:2:0:0 handle=\_SB_.PCI0.PEG3.MXM3
dev.hostb.15.%location: pci0:255:5:3
dev.hostb.14.%location: pci0:255:5:2
You can then find the parent using the %parent OID. For instance, the parent of pci0:2:0:0 (listed in the example above) is pci1:
$ sysctl dev.vgapci.0.%parent
dev.vgapci.0.%parent: pci1
The parent has its own sysctl tree:
$ sysctl dev.pcib.1.%location
dev.pcib.1.%location: pci0:0:3:0 handle=\_SB_.PCI0.PEG3
Not the most straightforward approach, but it should work accross different versions of FreeBSD (and probably DragonFlyBSD FWIW).
Try devinfo -rv.
A snippet of output on FreeBSD 10.3:
atapci1 pnpinfo vendor=0x8086 device=0x27c0 subvendor=0x1043 subdevice=0x8179 class=0x01018f at p
ci0:0:31:2 handle=\_SB_.PCI0.IDE1
Interrupt request lines:
0x13
I/O ports:
0xb880-0xb88f
0xbc00-0xbc03
0xc000-0xc007
0xc080-0xc083
0xc400-0xc407
ata2 at channel=0
ata3 at channel=1

Resources