Nginx代码调试——gdb工具
参考网上的资料,写了一个configprint模块,其功能为打印输出location配置内容,并计数访问次数。
代码链接如下:https://github.com/PaulWeiHan/nginx_module_development
程序的编写到运行总不是一帆风顺的,编译通过,运行不过的情况是最让我抓狂的。
这里记录一下gdb调试过程。供大家参考:
(这里没有gdb命令说明,请自行百度)
我使用的是nginx的默认模式即:
daemon on; master_process on; worker_processes 1;
我们知道。nginx默认执行的时候,是以daemon模式运行在后台,并且,由master进程fork出多个work子进程来监听端口的。切到nginx目录,执行下面命令:
1 gdb 2 shell sbin/nginx 3 shell pidof nginx
这样,我们就可以得到nginx的pid,一般会是两个,由于worker子进程是fork master得来的,所以自然worker进程的pid较大。利用gdb的attach和detach命令追踪worker子进程。
(gdb) shell pidof nginx 11903 11902 (gdb) attach 11903 Attaching to process 11903 Reading symbols from /home/renwh/nginx/sbin/nginx...done. Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done. [Thread debugging using libthread_db enabled] Loaded symbols for /lib64/libpthread.so.0 Reading symbols from /lib64/libcrypt.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libcrypt.so.1 Reading symbols from /lib64/libpcre.so.0...(no debugging symbols found)...done. Loaded symbols for /lib64/libpcre.so.0 Reading symbols from /lib64/libz.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libz.so.1 Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Reading symbols from /lib64/libfreebl3.so...(no debugging symbols found)...done. Loaded symbols for /lib64/libfreebl3.so Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/libdl.so.2 Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/libnss_files.so.2 0x00000031684e8fb3 in __epoll_wait_nocancel () from /lib64/libc.so.6 Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.x86_64 nss-softokn-freebl-3.14.3-17.el6.x86_64 pcre-7.8-6.el6.x86_64 zlib-1.2.3-29.el6.x86_64 (gdb)
子进程即worker进程在运行后会停留在epoll_wait处等待相应的事件发生,而这个函数调用被封装在ngx_process_events_and_timers 中。于是我们在这个函数出设置一个断点:b ngx_process_events_and_timers.然后采用命令c,使得nginx一直运行,直到遇到第一个断点:
1 (gdb) b ngx_process_events_and_timers 2 Breakpoint 1 at 0x41b565: file src/event/ngx_event.c, line 195. 3 (gdb) c 4 Continuing. 5 6 Breakpoint 1, ngx_process_events_and_timers (cycle=0x9be050) at src/event/ngx_event.c:195 7 195 { 8 (gdb)
进去之后,一直用n向下运行,直到找到ngx_process_events,然后用s追踪进该函数,一直n,直到运行到epoll_wait,发现,停在了这里,我们知道work子进程在等待事件了。
Breakpoint 1, ngx_process_events_and_timers (cycle=0x9be050) at src/event/ngx_event.c:195 195 { (gdb) n 199 if (ngx_timer_resolution) { (gdb) n 204 timer = ngx_event_find_timer(); (gdb) n 218 if (ngx_use_accept_mutex) { (gdb) n 240 delta = ngx_current_msec; (gdb) n 242 (void) ngx_process_events(cycle, timer, flags); (gdb) s ngx_epoll_process_events (cycle=0x9be050, timer=18446744073709551615, flags=1) at src/event/modules/ngx_epoll_module.c:702 702 { (gdb) n 717 events = epoll_wait(ep, event_list, (int) nevents, timer); (gdb) n
这时候,你只需要打开一个浏览器,访问你配置好的nginx模块的url,然后你就会发现gdb可以向下运行了。这时候,你需要在你自己的handler函数处设置断点,然后c,你会发现,又一次调用了ngx_process_events_and_timers函数,s进入函数,继续c运行,然后gdb会停在你自己的handler函数入口,这里是:ngx_http_configprint_handler。s追踪进去,你就可以单步执行你自己写的handler函数,进行debug了。
1 (gdb) b ngx_http_configprint_handler 2 Breakpoint 2 at 0x4699a7: file /home/renwh/src/nginx-1.9.2/configprint//ngx_http_configprint_module.c, line 184. 3 (gdb) c 4 Continuing. 5 6 Breakpoint 1, ngx_process_events_and_timers (cycle=0x9be050) at src/event/ngx_event.c:195 7 195 { 8 (gdb) s 9 199 if (ngx_timer_resolution) { 10 (gdb) n 11 204 timer = ngx_event_find_timer(); 12 (gdb) n 13 218 if (ngx_use_accept_mutex) { 14 (gdb) n 15 240 delta = ngx_current_msec; 16 (gdb) c 17 Continuing. 18 19 Breakpoint 2, ngx_http_configprint_handler (r=0x9c8550) 20 at /home/renwh/src/nginx-1.9.2/configprint//ngx_http_configprint_module.c:184 21 184 { 22 (gdb) n 23 189 u_char ngx_my_string[1024] = {0}; 24 (gdb) n 25 193 ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "ngx_http_configprint_handler is
gdb不光可以帮你debug,还可以帮你理解整个nginx的运行过程。你可以尝试在自己的handler挂载函数,loc_conf创建函数等地方添加断点,来查看整个模块的调用过程。
个人理解,欢迎讨论。联系方式:rwhsysu@163.com