如何调试用C编写并在Apache2中运行的cgi程序?

时间:2014-05-01 00:48:24

标签: c eclipse apache gdb cgi

我有一个用C编写的复杂cgi可执行文件,我在Apache2中配置,现在它已成功运行。如何在源代码中调试此程序,例如设置断点和检查变量?像gdb或eclipse这样的工具?有关如何设置调试环境的任何教程吗?

提前致谢!!

5 个答案:

答案 0 :(得分:7)

CGI接口基本上包括将HTTP请求传递给可执行文件的标准输入并在标准输出上获取响应。因此,您可以将测试请求写入文件并手动执行CGI,而无需使用Apache。然后可以使用GDB完成调试:

gdb ./my_cgi
>> break some_func
>> run < my_req.txt

my_req.txt包含完整请求:

GET /some/func HTTP/1.0
Host: myhost

如果您绝对需要由Apache运行CGI,那么将GDB附加到正确的进程可能会变得棘手。例如,您可以将Apache配置为只有一个工作进程,使用gdb -p附加到它,并使用set follow-fork-mode child确保它在请求到达时切换到CGI进程。

答案 1 :(得分:2)

我这样做了:在cgi main中我添加了代码来查找现有文件,比如/ var / tmp / flag。虽然存在,但我在循环中运行。足够的时间通过gdb附加到cgi进程。之后我删除/ var / tmp / flag,从现在开始我可以调试我的cgi代码。

bool file_exists(const char *filename)
{
   ifstream ifile(filename);
   return ifile;
}

int cgiMain()
{

    while (file_exists ("/var/tmp/flag"))
    sleep (1);
    ...
    your code 

答案 2 :(得分:1)

除非使用FastCGI或SCGI,否则CGI进程是短暂的,您需要延迟其退出,以便在进程仍在运行时有足够的时间连接调试器。对于随意调试,最简单的选择是在断点位置的无限循环中简单地使用sleep(),并在将调试器附加到程序后退出循环。

这是一个小例子CGI程序:

#include <stdio.h>
#include <unistd.h>

void wait_for_gdb_to_attach() {
  int is_waiting = 1;
  while (is_waiting) {
    sleep(1); // sleep for 1 second
  }
}

int main(void) {
  wait_for_gdb_to_attach();
  printf("Content-Type: text/plain;charset=us-ascii\n\n");
  printf("Hello!");
  return 0;
}

假设它被编译为cgi-debugging-example,这是应用程序进入无限循环后附加调试器的方式:

sudo cgdb cgi-debugging-example $(pgrep cgi-debugging)

接下来,您需要退出无限循环和wait_for_gdb_to_attach()函数以到达&#34;断点&#34;在你的申请中。这里的技巧是逐步退出睡眠功能,直到达到wait_for_gdb_to_attach()并使用调试器设置变量is_waiting的值,以便while (is_waiting)退出:

(gdb) finish
Run till exit from 0x8a0920 __nanosleep_nocancel () at syscall-template.S:81
0x8a07d4 in __sleep (seconds=0) at sleep.c:137
(gdb) finish
Run till exit from 0x8a07d4 in __sleep (seconds=0) at sleep.c:137
wait_for_gdb_to_attach () at cgi-debugging-example.c:6
Value returned is $1 = 0
(gdb) set is_waiting = 0 # <<<<<< to exit while
(gdb) finish
Run till exit from wait_for_gdb_to_attach () cgi-debugging-example.c:6
main () at cgi-debugging-example.c:13

离开wait_for_gdb_to_attach()后,您可以继续调试程序或让它运行完成。

详细说明的完整示例here

答案 3 :(得分:0)

我不确定如何在eclipse中使用gdb或其他前端,但是我只是用gdb调试了CGI程序。我想分享一些其他答案未提及的内容,即CGI通常需要使用RFC 3875#4.1读取getenv(3)中定义的请求元变量。我认为流行的请求变量是:

  • SCRIPT_NAME
  • QUERY_STRING
  • CONTENT_LENGTH
  • CONTENT_TYPE
  • REMOTE_ADDR

http服务器(例如Apache)提供了变量。使用gdb进行调试时,我们需要使用set environment自行设置这些值。就我而言,只需要几个变量a(并且源代码很旧,它仍然使用SCRIPT_URL而不是SCRIPT_NAME),所以这是我的示例:

gdb cgi_name
set environment SCRIPT_URL /path/to/sub/cgis
set environment QUERY_STRING p1=v1&p2=v2
break foo.c:42
run

答案 4 :(得分:0)

对我来说,上面介绍的在没有 Web 服务器的情况下在 gdb 中调试 CGI 的两种解决方案都不起作用。

也许第二种解决方案适用于 GET 请求。

我需要两者的结合,首先从 rfc3875 设置环境变量(不确定是否真的需要所有这些)。 然后我只能通过文件中的 STDIN 传递参数(而不是完整的请求)。

gdb cgi_name
set environment REQUEST_METHOD=POST
set environment CONTENT_LENGTH=1337
set environment CONTENT_TYPE=application/json
set environment SCRIPT_NAME=my.cgi
set environment REMOTE_ADDR=127.0.0.1

run < ./params.txt

使用 params.txt:

{"user":"admin","pass":"admin"}