调试Nginx模块崩溃需四步协同:一确保Nginx与模块均带-g-O0调试符号;二精准附加崩溃worker进程;三在入口、钩子、内存操作点设断点并捕获SIGSEGV;四结合debug日志、core转储交叉验证。

调试 Nginx 模块崩溃,核心是让 GDB 真正“看到”你的模块代码和运行上下文。这不单是启动 GDB 附加进程那么简单,关键在于编译、符号、触发路径和断点设置的协同。
确保模块与 Nginx 均带完整调试符号
没有调试符号,GDB 只能显示汇编或地址,无法定位到 C 源码行。必须在编译时显式启用:
- Nginx 编译需加 --with-debug 参数,并确保 CFLAGS="-g -O0"(关闭优化,保留变量和行号)
- 你的模块 Makefile 或 configure 脚本中,同样要传递 -g -O0,避免模块对象文件剥离符号
- 验证方法:运行 file /path/to/nginx 和 file objs/your_module.so,输出应含 “with debug_info”;用 nm -C your_module.o | grep your_function_name 确认函数符号存在
精准附加正在崩溃的 worker 进程
Nginx 多 worker 架构下,崩溃通常只发生在某个特定 worker。盲目附加 master 进程无意义:
- 先用 ps aux | grep nginx 找出所有 worker PID(注意排除 master 和 cache manager)
- 若已知复现路径(如访问某 URL 必然崩溃),可在请求前用 nginx -s stop && nginx -g "daemon off;" 启动前台单 worker 模式,再用 gdb --args /path/to/nginx -c /path/to/nginx.conf 直接调试主进程
- 若崩溃偶发,可配置 worker_processes 1; + daemon off; 降低干扰,再用 gdb -p [worker_pid] 附加
在关键位置设断点并捕获崩溃现场
崩溃常由空指针解引用、内存越界或非法状态引发。不要等 Segmentation fault 再行动:
- 在模块入口函数(如 ngx_http_your_handler)、回调钩子(ngx_http_your_filter)、内存分配/释放点(ngx_palloc, ngx_free)提前下断点
- 启用 GDB 的崩溃捕获:handle SIGSEGV stop print,这样一触发段错误就自动中断,可立即执行 bt full 查看完整调用栈和寄存器值
- 检查可疑变量:用 print *(your_struct_ptr) 或 x/10xw (char_ptr-4) 查看内存周边,确认是否为野指针或已释放内存
结合日志与核心转储交叉验证
GDB 提供运行时快照,Nginx 日志和 core 文件提供上下文佐证:
- 开启 Nginx error_log debug:error_log /path/to/error.log debug;,它会记录模块调用链、内存地址分配、配置加载细节
- 允许生成 core:ulimit -c unlimited 并在 nginx.conf 中设 working_directory /tmp;,崩溃后用 gdb /path/to/nginx /tmp/core.xxx 分析离线现场
- 对比 GDB 中 info registers 的 $rip(崩溃指令地址)与日志中最后一条 trace 行,确认是否进入预期逻辑分支
调试本质是缩小不确定性范围。从符号完整性出发,锁住具体 worker,用断点拦截异常前一刻,再借日志与 core 锁定根因——每一步都不可跳过。

















