调试nginx1.0.15:
举个实例:
如何让nignx以单进程运行(不以master和worker,不进入后台)方便调试:
main():408以单进程启动的代码: if (ngx_process == NGX_PROCESS_SINGLE) {ngx_single_process_cycle(cycle);} 全局变量ngx_process赋值的地方只有一个 main():363 if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { ngx_process = NGX_PROCESS_MASTER;} 所以,ccf->master为0即可单进程启动。这个是配置项,master在nginx.conf没有,所以看worker_processes是如何设置的。 修改配置文件,将worker_processes改为3。启动调试,在变量cycle初始化之后添加观察点: gdb nginx b main r # line 333: cycle = ngx_init_cycle(&init_cycle); #进入main断点,运行到cycle初始化之后即333行 u 334 # 设置观察点 watch (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes u 362 # 发现没有修改这个值。查看一下这个值: p (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes # 已经变为了3,所以就是333行初始化的,所以进入ngx_init_cycle看看。 # 删除所有的断点,重启配置 delete b ngx_init_cycle r # 观察这个函数,找到cycle和ccf初始化的地方(notepad++选中cycle即可看出它在什么地方赋值),先执行到cycle初始化的地方: # line 79: cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); u 80 p cycle->conf_ctx # 这个时候还没有初始化ccf,观察一下cycle->conf_ctx初始化的地方,执行到这里: # line 188: cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); l 188 u 189 p (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes # 发现这个时候conf_ctx还没有初始化为数组,所以再观察: # line 228: cycle->conf_ctx[ngx_modules[i]->index] = rv; u 228 n p (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes # 发现这个时候值为-1(还没有加载配置),所以可以设置观察点: watch (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes # 观察可能改变这个值的代码,应该在line 268: ngx_conf_parse这个地方最有可能会改变,执行到这里: u 269 # 这个时候发现改变了,是函数ngx_conf_set_num_slot设置了这个值,所以设置断点,重启程序: # Hardware watchpoint 30: (*(ngx_core_conf_t*)cycle->conf_ctx[0]).worker_processes # Old value = -1 # New value = 3 # ngx_conf_set_num_slot (cf=0x7fffffffe610, cmd=0x6bbaf8, conf=0x6dca70) at src/core/ngx_conf_file.c:1201 delete b ngx_conf_set_num_slot r # 进入断点ngx_conf_set_num_slot,查看调用堆栈: bt #0 ngx_conf_set_num_slot (cf=0x7fffffffe610, cmd=0x6bbaf8, conf=0x6dca70) at src/core/ngx_conf_file.c:1186 #1 0x000000000041c0e1 in ngx_conf_handler (cf=0x7fffffffe610, last=0) at src/core/ngx_conf_file.c:394 #2 0x000000000041bc7f in ngx_conf_parse (cf=0x7fffffffe610, filename=0x6dbce0) at src/core/ngx_conf_file.c:244 #3 0x00000000004189b0 in ngx_init_cycle (old_cycle=0x7fffffffe760) at src/core/ngx_cycle.c:268 #4 0x00000000004038d0 in main (argc=1, argv=0x7fffffffea28) at src/core/nginx.c:333 # 可以完全的发现如何调用的配置了。 # ngx_conf_parse:173 rc = ngx_conf_read_token(cf); 读取一个配置项,可以设断点看看。 # ngx_conf_handler:289 name = cf->args->elts; 取出配置名称: # (gdb) p *name # $48 = {len = 16, data = 0x6dcc20 "worker_processes"} # ngx_conf_handler:303 cmd = ngx_modules[i]->commands; 循环处理所有的命令,查看这个commands,实际上就是全局变量 ngx_core_commands # 在 ngx_core_commands 中可以发现,可以设置master_process来设置master,关于offsetof就是计算偏移量。 # ngx_conf_handler:394 rv = cmd->set(cf, cmd, conf); 就是调用这个回调函数(ngx_core_commands中定义),进入 ngx_conf_set_num_slot 修改配置文件,增加配置项 master_process off; 启动调试: delete b ngx_conf_set_flag_slot #进入断点,可以看到cmd为设置master: # (gdb) p *cmd # $50 = {name = {len = 14, data = 0x49d702 "master_process"}, type = 16843264, set = 0x41d58e <ngx_conf_set_flag_slot>, conf = 0, offset = 8, post = 0x0} 直接设置main的断点,看作用如何: delete r u 362 # 还需要设置daemon为off u 372 n # ccf->master和ccf->daemon这时候为0,会以单进程启动: u 408 # 发现调用了ngx_single_process_cycle(cycle);可以了。 # origin:15132 master:0 worker:0 listen-80:(15132/nginx)