分享我的调试技巧

程序员的百科全书Stack Overflow+Quora

Stack Overflow 程序员的百科全书
Quora 不仅限于编程方面的问答
Github 程序员的社交网络

神奇的四步编程法则

How to Program (in four easy steps)
How to Program (in four easy steps)

万能的Google

如何打开Google

由于GFW的存在,需要使用一些特殊的手段才能打开Google,常见的有VPN/GoAgent/Shadowsocks,也可以通过一些Google镜像
google搜索镜像
Google 镜像站搜集

如何使用Google

如何用好 Google 等搜索引擎?
英文版使用技巧
Get More Out of Google
中文版使用技巧
从谷歌搜获更多

Kernel调试

最基本的调试手段printk
内核选项配置

1
2
3
4
5
6
7
8
9
make menuconfig
Global build settings --->
[*] Enable support for printk
[*] Enable printk timestamps
make kernel_menuconfig
Kernel hacking --->
printk and dmesg options --->
[*] Show timing information on printks
(4) Default message log level (1-7)

手动调整打印级别

1
root@OpenWrt:~# cat /proc/sys/kernel/printk

允许所有级别的打印

1
root@OpenWrt:~# echo 8 > /proc/sys/kernel/printk

禁止所有打印输出

1
root@OpenWrt:~# echo 0 > /proc/sys/kernel/printk

还可通过启动参数bootargs调整默认打印级别

1
db120> setenv bootargs "$bootargs loglevel=0"

更多启动参数
Linux 内核引导参数简介

sys和proc

很多内核模块本身提供了sys或proc接口,方便和用户空间交互

1
2
3
4
5
6
7
8
9
10
11
root@OpenWrt:~# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
root@OpenWrt:~# sysctl -w net.ipv4.ip_forward=0
net.ipv4.ip_forward = 0
root@OpenWrt:~# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
root@OpenWrt:~#
root@OpenWrt:~# cat /proc/cmdline
root@OpenWrt:~# cat /proc/mtd
root@OpenWrt:~# cat /proc/net/arp
root@OpenWrt:~# cat /proc/net/route

DEBUG开关

很多内核模块、子系统和驱动源代码本身包含了一些关键点的调试代码,只是默认的调试开关未定义,例如:

1
2
3
4
5
6
7
huzhifeng@Ubuntu1404:~/git/OpenWrt/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.18.8$ grep -rwn "\-DDEBUG" drivers/usb/
drivers/usb/usbip/Makefile:1:ccflags-$(CONFIG_USBIP_DEBUG) := -DDEBUG
drivers/usb/chipidea/Makefile:1:ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
drivers/usb/dwc3/Makefile:4:ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
drivers/usb/gadget/Makefile:4:subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
drivers/usb/dwc2/Makefile:1:ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
drivers/usb/wusbcore/Makefile:1:ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG

只需要启用相应的调试开关如CONFIG_USBIP_DEBUGCONFIG_USB_CHIPIDEA_DEBUGCONFIG_USB_DWC3_DEBUGCONFIG_USB_GADGET_DEBUGCONFIG_USB_DWC2_DEBUGCONFIG_USB_WUSB_CBAF_DEBUG

dmesg

dmesg包含内核启动信息,热插拔信息,异常信息,既可以直接查看dmesg信息中有无异常,也可以对比正常和异常时的dmesg信息,从而定位问题

1
2
3
4
5
root@OpenWrt:~# dmesg | grep tty
[ 0.700000] console [ttyS0] disabled
[ 0.730000] serial8250.0: ttyS0 at MMIO 0x18020000 (irq = 11, base_baud = 2500000) is a 16550A
[ 0.730000] console [ttyS0] enabled
root@OpenWrt:~#

Oops

Objdump
TODO

其它技巧LKP

当需要添加较多的打印调试语句时,可以在include/linux/module.h或者include/linux/init.h中自定义一个打印宏,如下:

1
2
3
4
5
#if DEBUG
#define LKP(fmt, args...) printk(KERN_EMERG "[LKP %s(), line %d, " fmt "]\n", __FUNCTION__, __LINE__, ##args)
#else
#define LKP(fmt, args...)
#endif

这样带来的好处有:

  1. 区分自己的调试语句
  2. 调试信息更加清晰,具体到哪个函数,哪一行代码都会打印出来
  3. 减少打字,简单追踪的话只需加入LKP(“”);
  4. 随时开关调试功能,稍加改进甚至可通过启动参数控制
  5. 方便清除调试代码

Vim下注释所有LKP调试语句

1
:%s/LKP/\/\/LKP/g

Vim下删除所有LKP调试语句

1
:g/LKP/d

Vim下删除所有LKP和LUP调试语句

1
:g/LKP\|LUP/d

Sed注释所有LKP调试语句

1
sed -i "s/LKP/\/\/LKP/g" test.c

Sed删除某一文件中的LKP调试语句

1
sed -i "/LKP/d" test.c

Sed删除某一目录以及其下子目录中所有的LKP调试语句

1
grep -rwl "LKP" test/ | xargs sed -i "/LKP/d"

User space

LUP

1
2
3
4
5
6
7
8
9
void LUP( char * s)
{
FILE *f = fopen("/dev/console", "w");
if (f == NULL) {
return;
}
fprintf(f, "%s\n", s);
fclose(f);
}

Luci

perror

1
2
local util = require "luci.util"
util.perror(“Value=” .. tostring(val))

对于变量类型的打印,最好使用tostring函数做类型转换
需要先执行rm -rf /tmp/luci-*,然后可以通过logread查看打印信息

1
root@OpenWrt:~# logread -f

示例:

06-debugging.md
如何调试和分析LUCI

Javascript

Javascript的调试一般使用console.log和alert,alert的交互性不够友好,用得比较少。
Google Chrome下按快捷键F12或者CTRL+SHIFT+J,即可打开Console控制台,允许执行任意的Javascript命令,例如:

主流浏览器自带的调试功能都很强大,整个HTTP交互过程一目了然。

Fiddler Proxy

正则表达式

Regex101

Makefile

示例

1
2
3
4
5
6
7
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$ vim Makefile +19
19 $(warning "huzhifeng warning test GZIP_SUPPORT=$(GZIP_SUPPORT)")
20 $(error "huzhifeng error test GZIP_SUPPORT=$(GZIP_SUPPORT)")
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$ make
Makefile:19: "huzhifeng warning test GZIP_SUPPORT=1"
Makefile:20: *** "huzhifeng error test GZIP_SUPPORT=1"。 停止。
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$

详见官网说明
8.12 Functions That Control Make

GCC

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$ vim unsquashfs.c +41
41 #if !defined(HUZHIFENG) && !defined(FOO)
42 #warning "huzhifeng test warning: Both HUZHIFENG and FOO are not defined"
43 #error "huzhifeng test error: Both HUZHIFENG and FOO are not defined"
44 #endif
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$ make
cc -O2 -I. -I/home/huzhifeng/temp/squashfs/lzma465/C -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"gzip\" -Wall -DGZIP_SUPPORT -DLZMA_SUPPORT -DXZ_SUPPORT -DXATTR_SUPPORT -DXATTR_DEFAULT -c -o mksquashfs.o mksquashfs.c
cc -O2 -I. -I/home/huzhifeng/temp/squashfs/lzma465/C -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"gzip\" -Wall -DGZIP_SUPPORT -DLZMA_SUPPORT -DXZ_SUPPORT -DXATTR_SUPPORT -DXATTR_DEFAULT -c -o compressor.o compressor.c
cc mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o sort.o progressbar.o read_file.o info.o restore.o process_fragments.o caches-queues-lists.o gzip_wrapper.o lzma_wrapper.o /home/huzhifeng/temp/squashfs/lzma465/C/Alloc.o /home/huzhifeng/temp/squashfs/lzma465/C/LzFind.o /home/huzhifeng/temp/squashfs/lzma465/C/LzmaDec.o /home/huzhifeng/temp/squashfs/lzma465/C/LzmaEnc.o /home/huzhifeng/temp/squashfs/lzma465/C/LzmaLib.o xz_wrapper.o xattr.o read_xattrs.o -lpthread -lm -lz -llzma -o mksquashfs
cc -O2 -I. -I/home/huzhifeng/temp/squashfs/lzma465/C -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"gzip\" -Wall -DGZIP_SUPPORT -DLZMA_SUPPORT -DXZ_SUPPORT -DXATTR_SUPPORT -DXATTR_DEFAULT -c -o unsquashfs.o unsquashfs.c
unsquashfs.c:42: warning: #warning "huzhifeng test warning: Both HUZHIFENG and FOO are not defined"
unsquashfs.c:43: error: #error "huzhifeng test error: Both HUZHIFENG and FOO are not defined"
make: *** [unsquashfs.o] 错误 1
huzhifeng@Ubuntu1404:~/temp/squashfs/squashfs4.3/squashfs-tools$

详见官网说明
5 Diagnostics

Shell

使用echo和logger打印调试

1
2
echo “foo bar” >> /dev/console
logger

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@OpenWrt:~# cat >> test.sh <<EOF
> echo "huzhifeng test shell: echo" >> /dev/console
> logger "huzhifeng test shell: logger \$0 \$1"
> EOF
root@OpenWrt:~# cat test.sh
echo "huzhifeng test shell: echo" >> /dev/console
logger "huzhifeng test shell: logger $0 $1"
root@OpenWrt:~# chmod +x test.sh
root@OpenWrt:~# ./test.sh arg1 arg2
huzhifeng test shell: echo
root@OpenWrt:~# logread | tail -n 1
Wed Aug 12 08:30:31 2015 user.notice root: huzhifeng test shell: logger ./test.sh arg1
root@OpenWrt:~#

EOF