Problems with gdb and 2.0.32

Jim Nance (jlnance@avanticorp.com)
Thu, 18 Dec 1997 07:36:21 -0500


Hi All,
I was playing around last night and found several annoying problems
with gdb. I was running the 2.0.32 kernel with Cyrix patches. I have
not tried under any other Linux kernel. I have tried the same program
under Digital Unix, and things seem to behave much better.
The program I am working on forks off a copy of gdb and talks to it
through a pipe (ie its a gdb front end). While trying to debug this,
I noticed several problems:

1) If gdb attaches to a process and dies while the process is stopped,
the process is left in a T state. It can not be killed or suspended
with ^C or ^Z from its controlling terminal. It can be killed with the
kill command.

2) If a program does a pipe(); fork(); and then the processes try to
talk to each other via the pipe, the writter will get a SIGPIPE
if the program is running in the debugger. It works fine if the
program is not in in the debugger.

3) If a program does a fork(); execv(); The execv will recieve a SIGTRAP
and dump core. This is with either the execv() happening in the child
or the parrent. The debugger is always attached to the parrent. This
also works w/o problem if I am not running in the debugger.

Unfortunatly I did not make snapshots of these problem as I encountered them.
At the time I was trying to work around them, and only this morning did it
occur to me that I should report this behavior. I am including the program
in its present form so that anyone interested in these problems can make
sure its not an error on my part.

Thanks,

Jim

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <errno.h>

#define Write(x,y) write(x, y, strlen(y))

int parseCmdLine(int ac, char **av, pid_t *pid, char **fname)
{
if(ac!=4) {return 1;}
if(strcmp(av[1],"-pid")) {return 2;}

*pid = strtol(av[2], NULL, 0);
*fname = av[3];
return 0;
}

int waitforstr(char *str, char *buff, size_t max, int fd)
{
size_t len = strlen(str);
size_t pos, i;

/* This is not really necessary, but it makes debugging more pleasant */
memset(buff, 0, max);

for(pos=0; pos<max-1; pos++) {
int rc;
do {
rc=read(fd, &buff[pos], 1);
} while(rc==-1 && errno==EINTR);
if(rc!=1) {
--pos;
break;
}
if(pos>=len-1) {
int OK=1;
for(i=0; i<len; i++) {
if(str[i]!=buff[pos-len+1+i]) {
OK=0;
break;
}
}
if(OK==1) {
break;
}
}
}
buff[pos+1]=0;
return pos+1;
}

int main(int ac, char **av)
{
struct stat buff;
pid_t pid;
char *fname;
char rbuff[8192];
int pipefd[2];
int gin[2];
int gout[2];
int nchr;

if(parseCmdLine(ac, av, &pid, &fname)) {
fprintf(stderr,"Bad command line\n");
return 1;
}

if(kill(pid, 0)) {
fprintf(stderr,"Can not attach to process %d\n", pid);
return 2;
}

if(stat(fname, &buff)) {
fprintf(stderr, "Can not access %s\n", fname);
return 3;
}

/* if(socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd)<0) {*/
/* perror("socketpair:");*/
/* return 4;*/
/* }*/

pipe(gin);
pipe(gout);
fflush(stdout);
if(!fork()) {
static char cmd[1024];
static char *argv[] = {"/bin/sh","-c",cmd,0};
sprintf(cmd,"exec gdb %s %d", fname, pid);
close(0);
close(1);
close(gin[1]);
close(gout[0]);
dup2(gin[0], 0);
dup2(gout[1], 1);
#if 0
Write(1,"xyz\n");
Write(1,"(gdb) ");
do {
Write(1,"# fun1 \n");
Write(1,"# main \n");
Write(1,"(gdb) ");
} while(1);
#endif
execv(argv[0],argv);
exit(-1);
}

close(gin[0]);
close(gout[1]);
waitforstr("(gdb) ", rbuff, sizeof(rbuff), gout[0]);

Write(gin[1], "bt\n");

while(1) {
waitforstr("\n", rbuff, sizeof(rbuff), gout[0]);
sleep(0);
}
}

-- 
----------------------------------------------------------------------------
Jim Nance                                                 Avant! Corporation
(919) 941-6655    Do you have sweet iced tea?       jim_nance@avanticorp.com
                  No, but theres sugar on the table.