PDA

View Full Version : Reading from a QProcess



drhex
29th February 2008, 22:49
I intend to simplify debuggning by having my program start gdb to automatically print a backtrace whenever the program crashes. The first stumbling block seems to be reading from a QProcess.

The program below deliberately causes a segfault and starts gdb from the signal handler. For now, I just want to read whatever gdb outputs and pass selected lines to the console. When I run this program, 9 times out of 10 it hangs after printing "about to start gdb". About every 10th time it manages to read and echo the first 10 or so lines of output from gdb.

I don't think getting gdb to start is a problem, as it always seems to start if I set the channel mode to ForwardedChannels (so that gdb prints directly to the console).

So my questions are:
1) Why doesn't this program do the same thing every time?
2) Why do I only get the first few lines of output? (the rest of the lines show up after I explicitly kill the gdb process)

QT 4.3.4, Linux Ubuntu 7.10




#include <QApplication>
#include <QProcess>

#include <signal.h>


void segv_handler(int)
{
qDebug("Caught SEGV");
QProcess pro;
pro.setProcessChannelMode(QProcess::MergedChannels );
//pro.setProcessChannelMode(QProcess::ForwardedChann els);
qDebug("about to start gdb");
pro.start("gdb", QStringList() << qApp->arguments().at(0) << qPrintable(QString::number(getpid())));
qDebug("waiting for start");
if (!pro.waitForStarted()) {
qDebug("Could not start gdb");
exit(1);
}
char buf[1024];
int len;
while(true) {
pro.waitForReadyRead();
do {
len = pro.readLine(buf, sizeof(buf));
if (len>0)
qDebug("%s", buf);
} while (len>0);
}
}


void cause_segv(int x)
{
*(int *)0 = x;
}


int main(int argc, char *argv[])
{
QApplication app(argc, argv);

signal(SIGSEGV, segv_handler);

cause_segv(25);

app.exec();
return 0;
}

wysota
1st March 2008, 00:05
How about using this instead?

http://www.thorsen-consulting.dk/freebies.html

By the way. When the application segfaults, you musn't call any Qt methods as the application is in an unpredictable state.

drhex
1st March 2008, 22:27
I tried the backtrace from thorsen consulting, it gave me a trace looking like this:

0: prog [0x8049989]
1: prog(__gxx_personality_v0+0x253) [0x8049427]
2: [0xffffe420]
3: prog(__gxx_personality_v0+0x16b) [0x804933f]
4: prog(__gxx_personality_v0+0x1c0) [0x8049394]
5: /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0) [0xb6e62050]
6: prog(__gxx_personality_v0+0xfd) [0x80492d1]



It looks the same whether the executable has debuginfo in it or not. :(

Some further testing show that the problems I had reading from gdb was not caused by calling Qt functions after a SEGV, it did not work better when calling segv_handler as an ordinary function either. With some more command line options, gdb becomes easier to control from another process:




#include <QApplication>
#include <QProcess>

#include <signal.h>

void segv_handler(int)
{
QProcess pro;
pro.setProcessChannelMode(QProcess::MergedChannels );
qDebug("Caught SEGV, trying to get a backtrace from gdb...");
pro.start("gdb", QStringList()
<< "-batch"
<< "-x" << "/home/drhex/src/foto/backtrace" // a file that just contains the word "backtrace"
<< qApp->arguments().at(0) << qPrintable(QString::number(getpid()))
,QIODevice::ReadOnly);
if (!pro.waitForStarted()) {
qDebug("Could not start gdb");
exit(1);
}
char buf[1024];
int len;
bool doprint = false;
do {
pro.waitForReadyRead();
do {
len = pro.readLine(buf, sizeof(buf));
if (len>0) {
QString s = buf;
if (s.indexOf("signal handler called") >-1) doprint = true;
s.chop(1); // skip newline
if (doprint) qDebug("%s", qPrintable(s));
}
} while (len>0);
} while(pro.state() == QProcess::Running);
exit(1);
}


void cause_segv(int x)
{
*(int *)0 = x;
}


int main(int argc, char *argv[])
{
QApplication app(argc, argv);

signal(SIGSEGV, segv_handler);

cause_segv(26);

app.exec();
return 0;
}


With the above program, I get the following output:


Caught SEGV, trying to get a backtrace from gdb...
#6 <signal handler called>
#7 0x0804983f in cause_segv (x=26) at prog.cc:42
#8 0x08049894 in main (argc=Cannot access memory at address 0x0
) at prog.cc:52

Line numbers, arguments, function names and file names, just like I wanted :)

drhex
1st March 2008, 22:37
Btw, I'd like to edit the first message in the thread again to change the subject line since it turned out to be more about debuggning than reading from QProcess, but it seems that it is not possible to edit old messages when new ones have been posted?

wysota
1st March 2008, 22:58
It is impossible to edit a post after some time (4 hours?) passes. You have to ask a moderator or an administrator to change the title for you.

jakebman
3rd July 2008, 17:51
If you start your program through gdb with a command like gdb myprogram, you'll have gdb monitoring your program throughout its execution. Since gdb catches signals, you can just let your program run and let gdb catch it when it SEGFAULTs.

caduel
3rd July 2008, 18:07
Why not just start your program (and gdb) in a shell?

Something like

ProgramThatMightCrash &
ITSPID=$!
gdb ProgramThatMightCrash $ITSPID