首页 > 解决方案 > 如何解决缺少 printk 输出的问题?

问题描述

我有两个相同的树莓派 3 b+ 设备,一个运行 raspberrypi-kernel_1.20180313-1,另一个运行 raspberrypi-kernel_1.20180417-1。我正在两个设备上使用“hcidump -R”观看蓝牙事件。一台设备显示蓝牙事件,另一台不显示。我已经交换了设备上的 SD 卡以确认它与硬件无关,无论 SD 卡在哪个设备中,运行 20180313 的设备都会显示蓝牙事件,而 20180417 则不会。

为了调试这个,我一直在从 git 提取的 raspbian 源中的各个点添加一些 printk 语句: https ://github.com/raspberrypi/linux

我觉得从调试开始最相关的地方是蓝牙 RX 代码,例如,为发送到线路规程的每个蓝牙消息打印一些内容。具体来说,在drivers/bluetooth/hci_ldisc.c中,在hci_uart_tty_receive函数中,我在开头加了两行:

printk(KERN_ERR "AARON: In hci_uart_tty_receive with tty %p\n", tty);
dump_stack();

重建内核并启动设备后,在运行 20180313 的 pi 上,我看到了日志消息/堆栈跟踪,而在另一个 pi 上,我什么也没看到,表明未达到蓝牙 RX 代码。所以为了进一步调试,我查看了堆栈跟踪,它是:

Jul  9 21:03:18 tiltpi kernel: [    9.391137] Workqueue: events_unbound flush_to_ldisc
Jul  9 21:03:18 tiltpi kernel: [    9.391166] [<8010f664>] (unwind_backtrace) from [<8010bd1c>] (show_stack+0x20/0x24)
Jul  9 21:03:18 tiltpi kernel: [    9.391183] [<8010bd1c>] (show_stack) from [<80449c20>] (dump_stack+0xc8/0x114)
Jul  9 21:03:18 tiltpi kernel: [    9.391221] [<80449c20>] (dump_stack) from [<7f4400cc>] (hci_uart_tty_receive+0x5c/0xac [hci_uart])
Jul  9 21:03:18 tiltpi kernel: [    9.391254] [<7f4400cc>] (hci_uart_tty_receive [hci_uart]) from [<804b9bdc>] (tty_ldisc_receive_buf+0x64/0x6c)
Jul  9 21:03:18 tiltpi kernel: [    9.391273] [<804b9bdc>] (tty_ldisc_receive_buf) from [<804ba15c>] (flush_to_ldisc+0xcc/0xe4)
Jul  9 21:03:18 tiltpi kernel: [    9.391293] [<804ba15c>] (flush_to_ldisc) from [<80135934>] (process_one_work+0x144/0x438)
Jul  9 21:03:18 tiltpi kernel: [    9.391311] [<80135934>] (process_one_work) from [<80135c68>] (worker_thread+0x40/0x574)
Jul  9 21:03:18 tiltpi kernel: [    9.391328] [<80135c68>] (worker_thread) from [<8013b930>] (kthread+0x108/0x124)
Jul  9 21:03:18 tiltpi kernel: [    9.391352] [<8013b930>] (kthread) from [<80107ed4>] (ret_from_fork+0x14/0x20)

我继续为 flush_to_ldisc 和 tty_ldisc_receive_buf 添加 printk 语句,重新编译和重新测试。但是,当我继续看到我在 hci_uart_tty_receive 中添加的 printk 消息时,我没有看到我添加到 flush_to_ldisc 或 tty_ldisc_receive_buf 中的消息。

在进一步检查内核源代码后,我发现堆栈跟踪甚至没有意义,因为列出的函数没有直接相互调用。更具体地说,在 tty_buffer.c 中,flush_to_ldisc(朝向堆栈底部)调用 receive_buf,然后调用 tty_ldisc_receive_buf,然后调用 hci_ldisc.c 中的 hci_uart_tty_receive。内核堆栈没有任何receive_buf 条目,并显示flush_to_ldisc 直接调用_tty_ldisc_receive_buf。

所以我很困惑。我搜索了内核源代码,没有发现“flush_to_ldisc”或“tty_ldisc_receive_buf”函数的其他声明。

为什么/如何 dump_stack() 缺少堆栈条目?为什么我放置在堆栈底部的函数中的 prink 语句没有显示,而我放置在堆栈顶部的 printk 语句确实显示了?

编辑:

更多搜索表明 Linux 内核依赖 gcc 进行某些优化,包括自动内联某些函数,因此这可能是我的堆栈跟踪发生的情况。这可以解释为什么我没有看到堆栈中明确列出的函数,但不能解释为什么 printk 输出没有出现。任何人对为什么 printk 语句会从堆栈顶部的函数而不是底部的函数中出现的任何想法?rsyslog.conf 文件设置为:

*.err                           -/var/log/errors.log

我添加的所有 printk 语句都类似于 "printk(KERN_ERR "string\n");"

EDIT2:更新了问题标题以反映它不仅仅是缺少 printk 输出。

EDIT3:我删除了内核源的本地副本,再次将其拉出,添加了我的 printk 语句,然后从头开始重新编译,现在我可以看到 printk 语句了。我添加的代码似乎没有重新编译或链接到内核构建中。我在制作内核之前运行了“make clean”,但似乎仍然没有正确编译/链接。但是开始 clean 解决了这个问题。

总结:Linux 内核利用 gcc 优化,这将导致函数被内联编译,即使在源代码中没有明确指定为内联。当你“确定”你已经用你的更改重新编译了内核时,你应该从一个干净的源代码/构建目录重新开始,并在将你的问题堆栈之前再次尝试。

标签: bluetoothlinux-kernellinux-device-driver

解决方案


推荐阅读