/* * This file is part of QDevelop, an open-source cross-platform IDE * Copyright (C) 2006 Jean-Luc Biord * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact e-mail: Jean-Luc Biord * Program URL : http://qdevelop.org * */ #include "debug.h" #include "editor.h" #include "registersimpl.h" #include #include #include #include // #ifdef Q_OS_LINUX #include #include #endif // #define QD qDebug() << __FILE__ << __LINE__ << ":" // Debug::Debug(QObject * parent, RegistersImpl *registersImpl, QString gdbName, Parameters p, QString exe, bool exeOnly) : QThread(parent) { m_parent = parent; m_registersImpl = registersImpl; m_gdbName = gdbName; executableName = exe; m_executeWithoutDebug = exeOnly; m_parameters = p; } // void Debug::run() { m_pid = 0; m_request = None; connect(m_parent, SIGNAL(debugCommand(QString)), this, SLOT(slotDebugCommand(QString)) ); connect(m_registersImpl, SIGNAL(debugCommand(QString)), this, SLOT(slotDebugCommand(QString)) ); connect(m_parent, SIGNAL(stopDebug()), this, SLOT(slotStopDebug()) ); connect(m_parent, SIGNAL(pauseDebug()), this, SLOT(slotPauseDebug()) ); connect(m_parent, SIGNAL(otherVariables(QStringList)), this, SLOT(slotOtherVariables(QStringList)) ); if( m_executeWithoutDebug ) executeWithoutDebug(); else launchDebug(); } // void Debug::executeWithoutDebug() { emit message( tr("Running...") ); processDebug = new QProcess(); connect(processDebug, SIGNAL(readyReadStandardOutput()), this, SLOT(slotMessagesDebug()) ); connect(processDebug, SIGNAL(readyReadStandardError()), this, SLOT(slotMessagesDebug()) ); setEnvironment( processDebug ); //processDebug->start("\""+executableName+"\"", QStringList() << m_parameters.arguments); //processDebug->start(executableName, QStringList() << m_parameters.arguments); // Divius: previous implementation will wrap all arguments in quotes processDebug->start("\""+executableName+"\"" + " " + m_parameters.arguments); processDebug->waitForFinished(500); // On attend un peu pour passer en �at Running while( processDebug->state() == QProcess::Running ) { processDebug->waitForFinished(5); } if (processDebug->exitCode() == 0) emit message( "---------------------- "+tr("Exited normally")+" ----------------------" ); else emit message( "---------------------- "+tr("Exited with error code %1").arg(processDebug->exitCode())+" ----------------------" ); emit endDebug(); } // void Debug::launchDebug() { emit message( tr("Debug...") ); processDebug = new QProcess(); connect(processDebug, SIGNAL(readyReadStandardOutput()), this, SLOT(slotMessagesDebug()) ); connect(processDebug, SIGNAL(readyReadStandardError()), this, SLOT(slotMessagesDebug()) ); setEnvironment( processDebug ); processDebug->start(m_gdbName, QStringList() << "--silent" << "--fullname" << executableName ); configureGdb(); writeMessagesToDebugger(); processDebug->write("run "+m_parameters.arguments.toLatin1()+"\n"); processDebug->waitForFinished(500); // On attend un peu pour passer en �at Running while( processDebug->state() == QProcess::Running ) { processDebug->waitForFinished(5); writeMessagesToDebugger(); } emit message( "---------------------- "+tr("Debug exited")+" ----------------------" ); } // void Debug::setEnvironment(QProcess *process) { process->setWorkingDirectory( m_parameters.workingDirectory ); process->setEnvironment( m_parameters.env ); } // void Debug::writeMessagesToDebugger() { QStringListIterator it(messagesToDebugger); while( it.hasNext() ) { QString msg = it.next(); processDebug->write( msg.toLatin1() ); } messagesToDebugger.clear(); } // void Debug::slotMessagesDebug() { char breakpoint[] = { 26, 26, 0x0 }; QString messages = processDebug->readAllStandardOutput(); if( m_executeWithoutDebug ) { slotMessagesError(); return; } static QString listMessagesDebug; listMessagesDebug += QString( messages ); if( !listMessagesDebug.endsWith("(gdb) ") ) { return; } while( listMessagesDebug.length() ) { QString s = listMessagesDebug.section("\n", 0, 0); listMessagesDebug = listMessagesDebug.section("\n", 1); if( !s.isEmpty() ) { if( s.indexOf( breakpoint )==0 ) { emit message( QString::fromUtf8(s.toLocal8Bit()) ); listVariables.clear(); listVariablesToSend.clear(); m_request = InfoScope; QString numLine = s.section(":", -4, -4); messagesToDebugger << "info scope "+numLine+"\n"; continue; } // if( s.indexOf("Program exited normally.") == 0 ) { emit message( QString::fromUtf8(s.toLocal8Bit()) ); slotStopDebug(); } else if( s.indexOf("[New Thread") == 0 && m_pid==0) { m_pid = s.section("(", 1, 1).section(" ", 1, 1).section(")", 0, 0).toInt(); } else if( m_request == Registers ) { s = "Registers:"+listMessagesDebug; emit message( QString::fromUtf8(s.toLocal8Bit()) ); listMessagesDebug.clear(); messagesToDebugger << "info sources\n"; m_request = InfoSources; } else if( m_request == InfoSources ) { if( s.indexOf("(gdb)") == 0) { m_request = None; s = "InfoSourcesEnd"; messagesToDebugger << "bt\n"; } else s = "InfoSources:"+s; emit message( QString::fromUtf8(s.toLocal8Bit()) ); } else if( m_request == InfoScope ) { if( s.indexOf("(gdb)") == 0 && listVariables.count() != 0 ) { foreach(QString s, m_otherVariables) { Variable v; v.name = s; v.kind = Debug::OtherArgs; listVariables.append( v ); } m_request = Whatis; Variable variable = listVariables.at(0); messagesToDebugger << "whatis "+variable.name+"\n"; } else if( s.contains( "No arguments" ) ) { if( listVariables.count() ) { foreach(QString s, m_otherVariables) { Variable v; v.name = s; v.kind = Debug::OtherArgs; listVariables.append( v ); } m_request = Whatis; Variable variable = listVariables.at(0); messagesToDebugger << "whatis "+variable.name+"\n"; } else { m_request = None; } } else if( s.indexOf("Symbol ") == 0 ) { QString name = s.section("Symbol ", 1).section(" ", 0, 0).simplified(); if( !name.isEmpty() ) { Variable variable; variable.name = name; variable.kind = Local; listVariables.append( variable ); } } } else if ( m_request == Whatis ) { QString type = s.section("type = ", 1).simplified(); if( !type.isEmpty() ) { Variable variable = listVariables.at(0); listVariables.removeAt( 0 ); variable.type = type; listVariables.prepend( variable ); m_request = Address; if( type.contains( "*" ) ) { messagesToDebugger << "p "+variable.name+"\n"; } else { messagesToDebugger << "p &"+variable.name+"\n"; } } } else if ( m_request == Address ) { QString address = s.section(" = ", 1).simplified(); if( !address.isEmpty() ) { Variable variable = listVariables.at(0); listVariables.removeAt( 0 ); variable.address = address; listVariables.prepend( variable ); if( variable.type.section(" ", 0, 0) == "QString" ) { m_request = Length; messagesToDebugger << "p "+variable.name+"->d.size\n"; } else { m_request = Value; if( variable.type.section(" ", 0, 0) == "string" ) messagesToDebugger << "p "+variable.name+".c_str()\n"; else messagesToDebugger << "p "+variable.name+"\n"; } } } else if ( m_request == Length ) { if( s.length() && s.at(0) == '$' ) { int length = s.section(" = ", 1).simplified().toInt(); Variable variable = listVariables.at(0); listVariables.removeAt( 0 ); if( length > 0 ) { variable.length = qMin(length, 100); listVariables.prepend( variable ); m_request = Value; messagesToDebugger << "p "+variable.name+"->d.data[0]\n"; } else { listVariablesToSend.append( variable ); if( listVariables.count() ) { Variable variable = listVariables.at(0); messagesToDebugger << "whatis "+variable.name+"\n"; m_request = Whatis; } else { emit debugVariables( listVariablesToSend ); listVariablesToSend.clear(); m_request = None; } } } } else if ( m_request == Value ) { s.remove( "(gdb) "); if( s.length() && s.at(0) == '$' ) { Variable variable = listVariables.at(0); listVariables.removeAt( 0 ); QString content = s.section("= ", 1); if( variable.type.section(" ", 0, 0) == "QString" ) { if( variable.length && variable.content.length() < variable.length ) { variable.content += QChar( content.toInt() ); m_request = Value; listVariables.prepend( variable ); messagesToDebugger << "p "+variable.name+"->d.data["+QString::number(variable.content.length())+"]\n"; continue; } else { listVariablesToSend.append( variable ); } } else { variable.content = QString::fromUtf8(content.toLocal8Bit()); listVariablesToSend.append( variable ); } if( listVariables.count() ) { variable = listVariables.at(0); messagesToDebugger << "whatis "+variable.name+"\n"; m_request = Whatis; } else { m_request = None; emit debugVariables( listVariablesToSend ); listVariablesToSend.clear(); listMessagesDebug.clear(); messagesToDebugger << "info register\n"; m_request = Registers; } } } else { emit message( QString::fromUtf8(s.toLocal8Bit()) ); } } } slotMessagesError(); } void Debug::slotMessagesError() { QStringList list = QString(processDebug->readAllStandardError()).split("\n"); if( list.count() ) foreach(QString s, list) { if( !s.isEmpty() ) { if( m_request != None ) { if( listVariables.count() ) { Variable variable = listVariables.at(0); variable.content = tr("Error: Unable to evaluate value"); listVariablesToSend.append( variable ); listVariables.removeAt( 0 ); } if( listVariables.count() ) { Variable variable = listVariables.at(0); messagesToDebugger << "whatis "+variable.name+"\n"; m_request = Whatis; } else { emit debugVariables( listVariablesToSend ); listVariablesToSend.clear(); m_request = None; } } else emit message( s ); } } list.clear(); } // void Debug::slotOtherVariables(QStringList list) { m_otherVariables = list; } // void Debug::slotDebugCommand(QString text) { if( text == "info sources\n" ) m_request = InfoSources; messagesToDebugger << text; } // void Debug::slotBreakpoint(QString filename, unsigned int line, BlockUserData *blockUserData) { QString point; if( blockUserData->breakpoint ) { if( blockUserData->isTrue ) { if( blockUserData->breakpointCondition.isEmpty() ) point = "break "+filename+":"+QString::number(line)+"\n"; else point = "break "+filename+":"+QString::number(line)+" if "+blockUserData->breakpointCondition+"\n"; } else { point = "watch "+blockUserData->breakpointCondition+"\n"; } } else point = "clear "+filename+":"+QString::number(line)+"\n"; messagesToDebugger << point; } // void Debug::slotStopDebug() { emit endDebug(); #ifdef Q_OS_LINUX if( m_pid ) { kill(m_pid, SIGKILL); m_pid = 0; } #endif processDebug->kill(); processDebug->deleteLater(); } // void Debug::slotPauseDebug() { #ifdef Q_OS_LINUX if( m_pid ) { kill(m_pid, SIGINT); emit onPause(); } #endif } // void Debug::configureGdb() { slotDebugCommand("set pagination off\n"); slotDebugCommand("set width 0\n"); slotDebugCommand("set height 0\n"); slotDebugCommand("set complaints 0\n"); // }