ubuntu gdb 多線程調試步驟

注:實驗代碼來自於網絡,在原代碼中只增加了一些打印代碼。

 

本文僅作複習筆記之用,以備日後查閱。

 

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <unistd.h>

#include <arpa/inet.h>

//#include <openssl/ssl.h>

//#include <openssl/err.h>

#include <fcntl.h>

#include <sys/epoll.h>

#include <sys/time.h>

#include <sys/resource.h>

#include <pthread.h>

#include <assert.h>

 

 

//#include "oci_api.h"

 

 

#define MAXBUF 1024

#define MAXEPOLLSIZE 100

 

 

/*

 setnonblocking ?C ???þ???Ϊ????????ʽ

 */

int setnonblocking(int sockfd)

{

  if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)

  {

    return -1;

  }

  return 0;

}

 

 

/*

 pthread_handle_message ?C ?̴߳??? socket ?ϵ???Ϣ?շ?

 */

void* pthread_handle_message(int* sock_fd)

{

  char recvbuf[MAXBUF + 1];

  char sendbuf[MAXBUF+1];

  int  ret;

  int  new_fd;

  struct sockaddr_in client_addr;

  socklen_t cli_len=sizeof(client_addr);

 

 

  new_fd=*sock_fd; 

 

 

  /* ??ʼ????ÿ????l???ϵ??????շ? */

  bzero(recvbuf, MAXBUF + 1);

  bzero(sendbuf, MAXBUF + 1);

 

 

  /* ???տͻ??˵???Ϣ */

  ret = recvfrom(new_fd, recvbuf, MAXBUF, 0, (struct sockaddr *)&client_addr, &cli_len);

  if (ret > 0){

    printf("socket: %d \n recv from : %s : %d \n message: %s \n ??%d bytes \n",

           new_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), recvbuf, ret);

  /* 

  char *s1="insert";

  char *s2="select";

  char *s3="delete";

 

 

  if(!strncmp(s1,recvbuf,6))

    oci_insert(recvbuf,sendbuf);

  else if(!strncmp(s2,recvbuf,6))

    oci_select(recvbuf,sendbuf);

  else if(!strncmp(s3,recvbuf,6))

    oci_delete(recvbuf,sendbuf);

  else

    sprintf(sendbuf,"input sql is error!/n");

 

 

   ret = sendto(new_fd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&client_addr, cli_len);

   if(ret<0)

     printf("??Ϣ????ʧ?ܣ???????????%d????????Ϣ??'%s'/n", errno, strerror(errno));

   */

 

 

  }

  else

  {

    printf("received failed! error code %d ??message : %s \n",

      errno, strerror(errno));    

  }

  /* ????ÿ????l???ϵ??????շ????? */ 

  //printf("pthread exit!");

  fflush(stdout); 

  pthread_exit(NULL);

}

 

 

 

 

 

int main(int argc, char **argv)

{

  int listener, kdpfd, nfds, n, curfds;

  socklen_t len;

  struct sockaddr_in my_addr, their_addr;

  unsigned int myport;

  struct epoll_event ev;

  struct epoll_event events[MAXEPOLLSIZE];

  struct rlimit rt;

 

 

  myport = 1234; 

 

 

  printf("port setting 1234 success \n");

 

  pthread_t thread;

  pthread_attr_t attr;

 

 

  /* ????ÿ?????????????????ļ??? */

  rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;

  if (setrlimit(RLIMIT_NOFILE, &rt) == -1) 

  {

    perror("setrlimit");

    exit(1);

  }

  else 

  {

    printf("setting success \n");

  }

 

    printf("setting success \n");

 

  /* ???? socket ???? */

  if ((listener = socket(PF_INET, SOCK_DGRAM, 0)) == -1)

  {

    perror("socket create failed ??");

    exit(1);

  }

  else

  {

    printf("socket create  success /n");

  }

 

 

    printf("3 setting success \n");

  /*????socket???ԣ??˿ڿ???????*/

  int opt=SO_REUSEADDR;

  setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

 

 

  setnonblocking(listener);

  bzero(&my_addr, sizeof(my_addr));

  my_addr.sin_family = PF_INET;

  my_addr.sin_port = htons(myport);

/*

  my_addr.sin_addr.s_addr = INADDR_ANY;

  */

 

  my_addr.sin_addr.s_addr = inet_addr("192.168.34.52");

   printf("4 setting success \n");

 

/*

  printf("socket : %s   \n", inet_ntoa((my_addr.sin_addr));

*/

 

  printf("socket : %s   \n", inet_ntoa(my_addr.sin_addr));

 

  if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) 

 

  {

 

  printf("socket : %s   \n", inet_ntoa(my_addr.sin_addr));

    perror("bind error! \n");

    exit(1);

  } 

  else

  {

    printf("IP and port bind success \n");

 

    printf("port: %d \n",ntohs(my_addr.sin_port));

  }

 

  /* ???? epoll ???????Ѽ??? socket ???뵽 epoll ?????? */

  kdpfd = epoll_create(MAXEPOLLSIZE);

  len = sizeof(struct sockaddr_in);

  ev.events = EPOLLIN | EPOLLET;

  ev.data.fd = listener;

  if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0) 

  {

    fprintf(stderr, "epoll set insertion error: fd=%d \n", listener);

    return -1;

  }

  else

  {

    printf("111112223333listen socket added in  epoll success \n");

  }

 

 

  while (1) 

  {

    /* ?ȴ????¼????? */

 

    printf("6666666listen socket added in  epoll success \n");

 

    printf("7777777 kdpfd values: %d \n",kdpfd);

    nfds = epoll_wait(kdpfd, events, 10,-1 );

    printf("nfds values: %d ",nfds);

    if (nfds == -1)

    {

      perror("epoll_wait \n");

      break;

    }

 

 

    printf(" epoll wait ok \n");

    /* ?????????¼? */

    for (n = 0; n < nfds; ++n)

    {

      if (events[n].data.fd == listener) 

      {

        /*??ʼ??????ֵ??????ΪĬ??ֵ*/

        pthread_attr_init(&attr);

        pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

 

 

        /*  ?????߳?Ϊ????????*/ 

        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

 

 

        if(pthread_create(&thread,&attr,(void*)pthread_handle_message,(void*)&(events[n].data.fd)))

        {

           perror("pthread_creat error!");

           exit(-1);

        } 

 

       } 

     }

  }

  close(listener);

  return 0;

}

 

查看目錄裏的內容:

說明:編譯udpepoll.c文件時,必須要加”-g“ 選項,要不後面無法用gdb調試。

root@ubuntu:/home/lin/epoll/udp# ls

udpepoll.c  up

up“爲編譯後的文件,通過gdb加載調試:

root@ubuntu:/home/lin/epoll/udp# gdb up

GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02

Copyright (C) 2012 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 "i686-linux-gnu".

For bug reporting instructions, please see:

<http://bugs.launchpad.net/gdb-linaro/>...

Reading symbols from /home/lin/epoll/udp/up...done.

(gdb) l 214

209     printf("6666666listen socket added in  epoll success \n");

210

211     printf("7777777 kdpfd values: %d \n",kdpfd);

212     nfds = epoll_wait(kdpfd, events, 10,-1 );

213     printf("nfds values: %d ",nfds);

214     if (nfds == -1)

215     {

216       perror("epoll_wait \n");

217       break;

218     }

查看斷點信息:

(gdb) info b

No breakpoints or watchpoints.

上面顯示無斷點,所以在代碼”udpepoll.c“文件中的 214行設置斷點:

(gdb) b 214

Breakpoint 1 at 0x8048fea: file udpepoll.c, line 214.

(gdb) c

The program is not being run.

執行程序:

(gdb) r

Starting program: /home/lin/epoll/udp/up 

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".

port setting 1234 success 

setting success 

setting success 

socket create  success /n3 setting success 

4 setting success 

socket : 192.168.34.52   

IP and port bind success 

port: 1234 

111112223333listen socket added in  epoll success 

6666666listen socket added in  epoll success 

7777777 kdpfd values: 8 

 

(gdb) r

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/lin/epoll/udp/up 

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".

port setting 1234 success 

setting success 

setting success 

socket create  success /n3 setting success 

4 setting success 

socket : 192.168.34.52   

IP and port bind success 

port: 1234 

111112223333listen socket added in  epoll success 

6666666listen socket added in  epoll success 

 

Breakpoint 1, main (argc=1, argv=0xbffff264) at udpepoll.c:211

211     printf("7777777 kdpfd values: %d \n",kdpfd);

(gdb) n

7777777 kdpfd values: 8 

212     nfds = epoll_wait(kdpfd, events, 10,-1 );

(gdb) 

213     printf("nfds values: %d ",nfds);

(gdb) 

214     if (nfds == -1)

(gdb) 

221     printf(" epoll wait ok \n");

(gdb) 

nfds values: 1  epoll wait ok 

223     for (n = 0; n < nfds; ++n)

(gdb) 

225       if (events[n].data.fd == listener) 

(gdb) 

228         pthread_attr_init(&attr);

(gdb) 

229         pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

(gdb) 

233         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

(gdb) 

236         if(pthread_create(&thread,&attr,(void*)pthread_handle_message,(void*)&(events[n].data.fd)))

查看線程信息:

(gdb) info threads

  Id   Target Id         Frame 

* 1    Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:236

(gdb) n

[New Thread 0xb7e06b40 (LWP 23450)]

223     for (n = 0; n < nfds; ++n)

(gdb) 

244   }

還是查看線程信息:

(gdb) info threads

  Id   Target Id         Frame 

  2    Thread 0xb7e06b40 (LWP 23450) "up" 0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6

* 1    Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:244

上面查到當前有兩個線程,看最前面的序號,”*1“ 是代表當前線程,而我們要進入線程裏進行調試,因此需要切換線程。

如下:

(gdb) thread 2

[Switching to thread 2 (Thread 0xb7e06b40 (LWP 23450))]

#0  0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6

再查看線程信息:

(gdb) info threads

  Id   Target Id         Frame 

* 2    Thread 0xb7e06b40 (LWP 23450) "up" 0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6

  1    Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:244

單步執行:

(gdb) n

Single stepping until exit from function clone,

which has no line number information.

0xb7fb4c80 in start_thread () from /lib/i386-linux-gnu/libpthread.so.0

(gdb) 

Single stepping until exit from function start_thread,

which has no line number information.

 

Breakpoint 2, pthread_handle_message (sock_fd=0xbfffec98) at udpepoll.c:51

51   socklen_t cli_len=sizeof(client_addr);

(gdb) 

54   new_fd=*sock_fd; 

注意:如下設置

(gdb) set scheduler-locking on

說明,多線程時,線程是同時運行的,要保證始終在本線程內調試,需做上述的操作。

 

(gdb) n

58   bzero(recvbuf, MAXBUF + 1);

(gdb) 

59   bzero(sendbuf, MAXBUF + 1);

(gdb) 

63   ret = recvfrom(new_fd, recvbuf, MAXBUF, 0, (struct sockaddr *)&client_addr, &cli_len);

查看變量值:

(gdb) p ret

$4 = 0

(gdb) n

64   if (ret > 0){

查看變量值:

(gdb) p ret

$5 = 10

查看從客戶端接收到是內容:

保存在recvbuf變量內。

(gdb) p recvbuf

$6 = "1122334488", '\000' <repeats 1014 times>

(gdb) 

 

說明:

上面的操作過程,有些步驟重複,主要該程序是服務器端程序,需要客戶端連接後,併發送數據。而實驗過程中忘記了從客戶端向服務器端發送數據包,當完成客戶端操作後,服務器調試時未從新操作,因此有了重複步驟。

 

客戶端使用網絡上的調試工具:


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章