利用gdb[i]调试nginx[ii]和利用gdb调试其他程序没有两样,只是nginx能够是daemon程序,也能够以多进程执行,因此利用gdb调试和寻常会有些许不一样。

当然,我们能够选择将nginx设置为非daemon模式并以单进程执行。而这需做例如以下设置就可以:

daemon off;

master_process off;

这是第一种情况:

这样的设置下的nginx在gdb下调试非常普通,过程能够[iii]是这样:

运行命令:

lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx

当前文件夹是在/usr/local/nginx/sbin,该文件夹下有运行程序nginx。上条命令也就是用gdb来開始调试nginx,进入gdb命令行,直接输入r就可以运行nginx:

(gdb) r

Starting program: /usr/local/nginx/sbin/nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

ngx_timer_resolution 1000000

由于nginx曾经台形式执行。键盘输入被nginx接管,此时无法输入gdb命令,因此须要按Ctrl+C退到gdb命令行模式,而nginx被中断暂停在__kernel_vsyscall调用里,输入bt命令能够查看到调用堆栈信息:

(gdb) r

Starting program: /usr/local/nginx/sbin/nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

ngx_timer_resolution 1000000

^C

Program received signal SIGINT, Interrupt.

0xb7f29430 in __kernel_vsyscall ()

(gdb) bt

#0  0xb7f29430 in __kernel_vsyscall ()

#1  0xb7e081a8 in epoll_wait () from /lib/tls/i686/cmov/libc.so.6

#2  0x08073ea3 in ngx_epoll_process_events (cycle=0x860ad60, timer=4294967295,

flags=0) at src/event/modules/ngx_epoll_module.c:405

#3  0x080668ee in ngx_process_events_and_timers (cycle=0x860ad60)

at src/event/ngx_event.c:253

#4  0×08071618 in ngx_single_process_cycle (cycle=0x860ad60)

at src/os/unix/ngx_process_cycle.c:283

#5  0x0804a926 in main (argc=1, argv=0xbfd2ae44) at src/core/nginx.c:372

(gdb)

好,来给nginx设置断点。这非常easy,比方这里给函数ngx_process_events_and_timers设置个断点,再输入命令c继续运行nginx:

#4  0×08071618 in ngx_single_process_cycle (cycle=0x860ad60)

at src/os/unix/ngx_process_cycle.c:283

#5  0x0804a926 in main (argc=1, argv=0xbfd2ae44) at src/core/nginx.c:372

(gdb) b ngx_process_events_and_timers

Breakpoint 1 at 0x80667d6: file src/event/ngx_event.c, line 200.

(gdb) c

Continuing.

Breakpoint 1, ngx_process_events_and_timers (cycle=0x860ad60)

at src/event/ngx_event.c:200

200  {

(gdb)

结果我这里gdb立即提示断点中断,这是由于恰好调到这个函数而已。或许在你那并不会立即中断。从而gdb就一直停在Continuing后面。此时我们就要主动去触发事件(或者等待,时间可能非常久,依据你的nginx设置)使得nginx调用这个函数。比方利用浏览器去訪问nginx监听的网站,使得nginx有事件发生。

断点中断后,利用s、c等gdb常规命令进行我们的调试,跟踪。这些无需多说:

200  {

(gdb) s

__cyg_profile_func_enter (this=0x80667d0, call=0×8071618)

at src/core/my_debug.c:65

warning: Source file is more recent than executable.

65      my_debug_print(“Enter\n%p\n%p\n”, call, this);

(gdb)

66    }

(gdb) c

Continuing.

ngx_timer_resolution 1000000

另外一种情况:

当以daemon模式(即配置选项:daemon on;)单进程执行nginx时,上面那种方法不凑效了。原因非常easy,当nginx以daemon模式执行时,这个启动过程中nginx将fork好几次。而那些父进程都早已直接退出了,因此看到的会这样:

lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx

GNU gdb 6.8-debian

Copyright (C) 2008 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type “show copying”

and “show warranty” for details.

This GDB was configured as “i486-linux-gnu”…

(gdb) r

Starting program: /usr/local/nginx/sbin/nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

Program exited normally.

(gdb)

而其实nginx并没有退出,退出的是其父(或祖父)进程,而gdb没有跟着fork跟踪下去:

lenky@lenky-desktop:/usr/local/nginx/sbin$ pidof nginx

7908

gdb考虑了这样的情况,因此也提供了对应的follow-fork-mode选项:

其使用方法为:

set follow-fork-mode [parent|child]

说明:

parent: fork之后继续调试父进程。子进程不受影响。

child: fork之后调试子进程。父进程不受影响。

设置了该选项后,其他调式操作和之前介绍的基本一样,相关示比例如以下:

lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx -q

(gdb) r

Starting program: /usr/local/nginx/sbin/nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

Program exited normally.

(gdb) shell pidof nginx

9723

(gdb) shell kill -9 9723

(gdb) set follow-fork-mode child

(gdb) b ngx_process_events_and_timers

Breakpoint 1 at 0x80667d6: file src/event/ngx_event.c, line 200.

(gdb) r

Starting program: /usr/local/nginx/sbin/nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

[Switching to process 9739]

Breakpoint 1, ngx_process_events_and_timers (cycle=0x8ff0d60)

at src/event/ngx_event.c:200

200  {

(gdb) s

[tcsetpgrp failed in terminal_inferior: No such process]

__cyg_profile_func_enter (this=0x80667d0, call=0×8071618)

at src/core/my_debug.c:65

warning: Source file is more recent than executable.

65      my_debug_print(“Enter\n%p\n%p\n”, call, this);

(gdb) c

Continuing.

上面我们先设置断点,这样执行r命令后nginx将自己主动被中断返回到gdb命令行。假设不这样做,那么将无法返回gdb命令行。即按Ctrl+C没有效果,由于nginx是以daemon模式执行的,输入输出已经被重定向,nginx没有接收到这个Ctrl+C输入。

当然也并非没有其他办法。比方另外一个shell窗体。利用kill命令给nginx进程发送一个SIGINT信号就可以,这和按Ctrl+C是一样的,例如以下(假定9897为nginx进程id号):

lenky@lenky-desktop:~$ sudo kill -2 9897

另外一种情况:

第三种情况就是无论nginx执行模式了,是通用的,即利用gdb的attach、detach命令。

假定当前nginx的相关配置这样:

daemon on;

master_process on;

worker_processes  1;

即daemon模式。多进程执行nginx。

lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb -q

(gdb) shell ./nginx

src/core/ngx_conf_file.c 1163 : 1000000

===============================

(gdb) shell pidof nginx

10246 10245

(gdb)

能够看到一共同拥有两个nginx进程,这里10245为master进程。而10246为worker进程。

我们要调试worker 10246能够例如以下:

(gdb) attach 10246

Attaching to program: /usr/local/nginx/sbin/nginx, process 10246

Reading symbols from /lib/tls/i686/cmov/libcrypt.so.1…done.

Loaded symbols for /lib/tls/i686/cmov/libcrypt.so.1

Reading symbols from /lib/libpcre.so.3…done.

Loaded symbols for /lib/libpcre.so.3

Reading symbols from /usr/lib/libz.so.1…done.

Loaded symbols for /usr/lib/libz.so.1

Reading symbols from /lib/tls/i686/cmov/libc.so.6…done.

Loaded symbols for /lib/tls/i686/cmov/libc.so.6

Reading symbols from /lib/ld-linux.so.2…done.

Loaded symbols for /lib/ld-linux.so.2

Reading symbols from /lib/tls/i686/cmov/libnss_compat.so.2…done.

Loaded symbols for /lib/tls/i686/cmov/libnss_compat.so.2

Reading symbols from /lib/tls/i686/cmov/libnsl.so.1…done.

Loaded symbols for /lib/tls/i686/cmov/libnsl.so.1

Reading symbols from /lib/tls/i686/cmov/libnss_nis.so.2…done.

Loaded symbols for /lib/tls/i686/cmov/libnss_nis.so.2

Reading symbols from /lib/tls/i686/cmov/libnss_files.so.2…done.

Loaded symbols for /lib/tls/i686/cmov/libnss_files.so.2

0xb8016430 in __kernel_vsyscall ()

(gdb) b ngx_process_events_and_timers

Breakpoint 3 at 0x80667d6: file src/event/ngx_event.c, line 200.

(gdb) c

Continuing.

Breakpoint 3, ngx_process_events_and_timers (cycle=0x8f43d68) at src/event/ngx_event.c:200

200  {

(gdb) detach

Detaching from program: /usr/local/nginx/sbin/nginx, process 10246

(gdb)

总的来看,还是第三种方法最顺手了。


[i] http://www.gnu.org/software/gdb/
[ii] nginx是打开了-g选项编译的。
[iii] 意思是说以下的方法仅仅是众多方法之中的一个。

nginx源代码分析--GDB调试的更多相关文章

  1. 新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t

    新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  2. 新秀nginx源代码分析数据结构篇(两) 双链表ngx_queue_t

    nginx源代码分析数据结构篇(两) 双链表ngx_queue_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn. ...

  3. Nginx源代码分析—业务流程

    Nginx源代码分析-业务流程 到此为止,我们如果ngx_init_cycle已经结束.我们临时无论他做了什么,我们从他做的效果进入. 从常理上来讲,假设一个请求到达,那么我们须要接受这个请求,那么就 ...

  4. nginx源代码分析--进程间通信机制 &amp; 同步机制

    Nginx源代码分析-进程间通信机制 从nginx的进程模型能够知道.master进程和worker进程须要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号, ...

  5. nginx源代码分析之内存池实现原理

    建议看本文档时结合nginx源代码. 1.1   什么是内存池?为什么要引入内存池? 内存池实质上是接替OS进行内存管理.应用程序申请内存时不再与OS打交道.而是从内存池中申请内存或者释放内存到内存池 ...

  6. nginx源代码分析--从源代码看nginx框架总结

    nginx源代码总结: 1)代码中没有特别绕特别别扭的编码实现.从变量的定义调用函数的实现封装,都非常恰当.比方从函数命名或者变量命名就能够看出来定义的大体意义,函数的基本功能,再好的架构实如今编码习 ...

  7. python 源代码分析之调试设置

    首先在官方下载源代码,我下载的是最新版本3.4.3版本:https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz 解压后的目录如下(借用网上的目 ...

  8. nginx源代码分析--配置文件解析

    ngx-conf-parsing 对 Nginx 配置文件的一些认识: 配置指令具有作用域,分为全局作用域和使用 {} 创建其他作用域. 同一作用域的不同的配置指令没有先后顺序:同一作用域能否使用同样 ...

  9. nginx源代码分析--模块分类

    ngx-modules Nginx 基本的模块大致能够分为四类: handler – 协同完毕client请求的处理.产生响应数据.比方模块, ngx_http_rewrite_module, ngx ...

随机推荐

  1. 数学图形(1.19)Doppler spiral螺线

    一种左右对称的螺线 相关软件参见:数学图形可视化工具,使用自己定义语法的脚本代码生成数学图形.该软件免费开源.QQ交流群: 367752815 vertices = t = *PI) to (*PI) ...

  2. 织梦(Dedecms) 5.1 feedback_js.php 注入漏洞

    漏洞版本: DEDECMS 5.1 漏洞描述: 同样是在magic_quotes_gpc=off的情况下可用 此漏洞可拿到后台管理员的帐号和加密HASH,漏洞存在文件plus/feedback_js. ...

  3. Quadro P5200 - 最强大的移动工作站显卡 专门为了惠普 VR Z 背包电脑而发布

    https://www.leiphone.com/news/201708/Z1MCetuoobEaHIqa.html 前言 在今年的计算机图形技术顶会 SIGGRAPH,英伟达并不是在单纯地展示自家的 ...

  4. 如何修改Git commit的信息

    原文地址: http://xiguada.org/change-git-commit-message   Git cimmit信息push后,如何修改,amend可以修改最后一次commit信息,但对 ...

  5. Thinkphp学习笔记-删除缓存

    Thinkphp的缓存数据在Cach文件夹下的Home文件夹下的文临时文件 清除方法:将缓存文件删除就可以了

  6. RS布局问题之块的不完美之完美

    早上一来,便传来喜讯...说我们做的报表太美.客户不敢看----于是便开启征程,亲自尝试了一把,如下面的操作,首次运行报表,在不考虑UI美观度的情况下,报表还是 在预测范围内显示的 那么接下来我们选择 ...

  7. 微软 Windows 10 将支持 8 英寸以下 ARM 平板设备

    2015 年 1 月 24 日,  9:32 下午 - 微软本周展示了 Windows 10 一系列新的改变,也包括首次公开展示的 Windows 10 手机版,但 ARM 平板并没有得到太多提及. ...

  8. angularjs中响应回车事件

    下面这个示例在输入框键入回车键或者点击按钮时,将输入框的值置为"Hello World!":(黄色背景内容为响应回车事件涉及到的代码) <html ng-app=" ...

  9. STL - C++ 11的Lambda表达式(下)

    关于lambda的基础知识,请参考上一篇的地址如下: http://www.cnblogs.com/davidgu/p/4825625.html 我们再举个STL使用Lambda来进行排序的例子,如下 ...

  10. 第一章:走近java-深入理解java虚拟机-读书总结

    java技术体系: 1.java程序设计语言 2.硬件平台上的java虚拟机 3.class文件格式 4.java的API类库 5.第三方的类库 JDK: java语言,虚拟机,java API类库  ...