Pass the result of ExprWind::exprList() in the return value.
[kdbg.git] / kdbg / dbgdriver.cpp
blob945ba88eda4076b4f8ff3bd24ffbaa50e7f0eca0
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include "dbgdriver.h"
8 #include "exprwnd.h"
9 #include <qstringlist.h>
10 #include <ctype.h>
11 #include <stdlib.h> /* strtol, atoi */
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 #include "mydebug.h"
16 #include <assert.h>
19 DebuggerDriver::DebuggerDriver() :
20 KProcess(),
21 m_state(DSidle),
22 m_output(0),
23 m_outputLen(0),
24 m_outputAlloc(0),
25 m_activeCmd(0),
26 m_promptMinLen(0),
27 m_promptLastChar('\0')
29 m_outputAlloc = 4000;
30 m_output = new char[m_outputAlloc];
32 m_prompt[0] = '\0';
33 // Derived classes can set either m_prompt or m_promptRE.
34 // If m_promptRE is set, it must include the '$' at the end.
35 // m_promptLastChar and m_promptMinLen must also be set.
37 m_hipriCmdQueue.setAutoDelete(true);
39 // debugger process
40 connect(this, SIGNAL(receivedStdout(KProcess*,char*,int)),
41 SLOT(slotReceiveOutput(KProcess*,char*,int)));
42 connect(this, SIGNAL(wroteStdin(KProcess*)), SLOT(slotCommandRead(KProcess*)));
43 connect(this, SIGNAL(processExited(KProcess*)), SLOT(slotExited(KProcess*)));
46 DebuggerDriver::~DebuggerDriver()
48 delete[] m_output;
51 int DebuggerDriver::commSetupDoneC()
53 TRACE(__PRETTY_FUNCTION__);
55 if (!KProcess::commSetupDoneC())
56 return 0;
58 close(STDERR_FILENO);
59 return dup2(STDOUT_FILENO, STDERR_FILENO) != -1;
63 bool DebuggerDriver::startup(QString cmdStr)
65 // clear command queues
66 delete m_activeCmd;
67 m_activeCmd = 0;
68 m_hipriCmdQueue.clear();
69 bool autodel = m_lopriCmdQueue.autoDelete();
70 m_lopriCmdQueue.setAutoDelete(true);
71 m_lopriCmdQueue.clear();
72 m_lopriCmdQueue.setAutoDelete(autodel);
73 m_state = DSidle;
75 // debugger executable
76 if (cmdStr.isEmpty())
77 cmdStr = defaultInvocation();
79 QStringList cmd = QStringList::split(' ', cmdStr);
80 clearArguments();
81 for (QStringList::iterator i = cmd.begin(); i != cmd.end(); ++i) {
82 *this << *i;
85 if (!start(KProcess::NotifyOnExit,
86 KProcess::Communication(KProcess::Stdin|KProcess::Stdout))) {
87 return false;
90 // open log file
91 if (!m_logFile.isOpen() && !m_logFileName.isEmpty()) {
92 m_logFile.setName(m_logFileName);
93 m_logFile.open(IO_WriteOnly);
96 // these must be set by derived classes in their constructor
97 assert(m_promptMinLen > 0); // _must_ have a prompt
98 assert(m_promptLastChar != '\0'); // last char _must_ be fixed
99 assert(m_prompt[0] == '\0' || strlen(m_prompt) == m_promptMinLen);
100 // either a prompt or a regexp
101 assert(m_prompt[0] != '\0' && m_promptMinLen < sizeof(m_prompt) ||
102 !m_promptRE.isEmpty() && m_promptRE.isValid());
104 return true;
107 void DebuggerDriver::slotExited(KProcess*)
109 static const char txt[] = "\n====== debugger exited ======\n";
110 if (m_logFile.isOpen()) {
111 m_logFile.writeBlock(txt,sizeof(txt)-1);
114 // reset state
115 m_state = DSidle;
116 // empty buffer
117 m_outputLen = 0;
118 *m_output = '\0';
122 CmdQueueItem* DebuggerDriver::executeCmdString(DbgCommand cmd,
123 QString cmdString, bool clearLow)
125 // place a new command into the high-priority queue
126 CmdQueueItem* cmdItem = new CmdQueueItem(cmd, cmdString);
127 m_hipriCmdQueue.enqueue(cmdItem);
129 if (clearLow) {
130 if (m_state == DSrunningLow) {
131 // take the liberty to interrupt the running command
132 m_state = DSinterrupted;
133 kill(SIGINT);
134 ASSERT(m_activeCmd != 0);
135 TRACE(QString().sprintf("interrupted the command %d",
136 (m_activeCmd ? m_activeCmd->m_cmd : -1)));
137 delete m_activeCmd;
138 m_activeCmd = 0;
140 flushLoPriQueue();
142 // if gdb is idle, send it the command
143 if (m_state == DSidle) {
144 ASSERT(m_activeCmd == 0);
145 writeCommand();
148 return cmdItem;
151 CmdQueueItem* DebuggerDriver::queueCmdString(DbgCommand cmd,
152 QString cmdString, QueueMode mode)
154 // place a new command into the low-priority queue
155 CmdQueueItem* cmdItem = 0;
156 switch (mode) {
157 case QMoverrideMoreEqual:
158 case QMoverride:
159 // check whether gdb is currently processing this command
160 if (m_activeCmd != 0 &&
161 m_activeCmd->m_cmd == cmd && m_activeCmd->m_cmdString == cmdString)
163 return m_activeCmd;
165 // check whether there is already the same command in the queue
166 for (cmdItem = m_lopriCmdQueue.first(); cmdItem != 0; cmdItem = m_lopriCmdQueue.next()) {
167 if (cmdItem->m_cmd == cmd && cmdItem->m_cmdString == cmdString)
168 break;
170 if (cmdItem != 0) {
171 // found one
172 if (mode == QMoverrideMoreEqual) {
173 // All commands are equal, but some are more equal than others...
174 // put this command in front of all others
175 m_lopriCmdQueue.take();
176 m_lopriCmdQueue.insert(0, cmdItem);
178 break;
179 } // else none found, so add it
180 // drop through
181 case QMnormal:
182 cmdItem = new CmdQueueItem(cmd, cmdString);
183 m_lopriCmdQueue.append(cmdItem);
186 // if gdb is idle, send it the command
187 if (m_state == DSidle) {
188 ASSERT(m_activeCmd == 0);
189 writeCommand();
192 return cmdItem;
195 // dequeue a pending command, make it the active one and send it to gdb
196 void DebuggerDriver::writeCommand()
198 // ASSERT(m_activeCmd == 0);
199 assert(m_activeCmd == 0);
201 // first check the high-priority queue - only if it is empty
202 // use a low-priority command.
203 CmdQueueItem* cmd = m_hipriCmdQueue.dequeue();
204 DebuggerState newState = DScommandSent;
205 if (cmd == 0) {
206 cmd = m_lopriCmdQueue.first();
207 m_lopriCmdQueue.removeFirst();
208 newState = DScommandSentLow;
210 if (cmd == 0) {
211 // nothing to do
212 m_state = DSidle; /* is necessary if command was interrupted earlier */
213 return;
216 m_activeCmd = cmd;
217 TRACE("in writeCommand: " + cmd->m_cmdString);
219 const char* str = cmd->m_cmdString;
220 writeStdin(const_cast<char*>(str), cmd->m_cmdString.length());
222 // write also to log file
223 if (m_logFile.isOpen()) {
224 m_logFile.writeBlock(str, cmd->m_cmdString.length());
225 m_logFile.flush();
228 m_state = newState;
231 void DebuggerDriver::flushLoPriQueue()
233 while (!m_lopriCmdQueue.isEmpty()) {
234 delete m_lopriCmdQueue.take(0);
238 void DebuggerDriver::flushHiPriQueue()
240 CmdQueueItem* cmd;
241 while ((cmd = m_hipriCmdQueue.dequeue()) != 0) {
242 delete cmd;
246 void DebuggerDriver::flushCommands(bool hipriOnly)
248 flushHiPriQueue();
249 if (!hipriOnly) {
250 flushLoPriQueue();
254 void DebuggerDriver::slotCommandRead(KProcess*)
256 TRACE(__PRETTY_FUNCTION__);
258 // there must be an active command which is not yet commited
259 ASSERT(m_state == DScommandSent || m_state == DScommandSentLow);
260 ASSERT(m_activeCmd != 0);
261 ASSERT(!m_activeCmd->m_committed);
263 // commit the command
264 m_activeCmd->m_committed = true;
266 // now the debugger is officially working on the command
267 m_state = m_state == DScommandSent ? DSrunning : DSrunningLow;
269 // set the flag that reflects whether the program is really running
270 switch (m_activeCmd->m_cmd) {
271 case DCrun: case DCcont: case DCnext: case DCstep: case DCfinish: case DCuntil:
272 emit inferiorRunning();
273 break;
274 default:
275 break;
278 // re-receive delayed output
279 if (m_delayedOutput.current() != 0) {
280 DelayedStr* delayed;
281 while ((delayed = m_delayedOutput.dequeue()) != 0) {
282 const char* str = delayed->data();
283 slotReceiveOutput(0, const_cast<char*>(str), delayed->length());
284 delete delayed;
289 void DebuggerDriver::slotReceiveOutput(KProcess*, char* buffer, int buflen)
292 * The debugger should be running (processing a command) at this point.
293 * If it is not, it is still idle because we haven't received the
294 * wroteStdin signal yet, in which case there must be an active command
295 * which is not commited.
297 if (m_state == DScommandSent || m_state == DScommandSentLow) {
298 ASSERT(m_activeCmd != 0);
299 ASSERT(!m_activeCmd->m_committed);
301 * We received output before we got signal wroteStdin. Collect this
302 * output, it will be re-sent by commandRead when it gets the
303 * acknowledgment for the uncommitted command.
305 m_delayedOutput.enqueue(new DelayedStr(buffer, buflen+1));
306 return;
308 // write to log file (do not log delayed output - it would appear twice)
309 if (m_logFile.isOpen()) {
310 m_logFile.writeBlock(buffer, buflen);
311 m_logFile.flush();
315 * gdb sometimes produces stray output while it's idle. This happens if
316 * it receives a signal, most prominently a SIGCONT after a SIGTSTP:
317 * The user haltet kdbg with Ctrl-Z, then continues it with "fg", which
318 * also continues gdb, which repeats the prompt!
320 if (m_activeCmd == 0 && m_state != DSinterrupted) {
321 // ignore the output
322 TRACE("ignoring stray output: " + DelayedStr(buffer, buflen+1));
323 return;
325 ASSERT(m_state == DSrunning || m_state == DSrunningLow || m_state == DSinterrupted);
326 ASSERT(m_activeCmd != 0 || m_state == DSinterrupted);
328 // collect output until next prompt string is found
330 // accumulate it
331 if (m_outputLen + buflen >= m_outputAlloc) {
333 * Must enlarge m_output: double it. Note: That particular
334 * sequence of commandes here ensures exception safety.
336 int newSize = m_outputAlloc * 2;
337 char* newBuf = new char[newSize];
338 memcpy(newBuf, m_output, m_outputLen);
339 delete[] m_output;
340 m_output = newBuf;
341 m_outputAlloc = newSize;
343 memcpy(m_output+m_outputLen, buffer, buflen);
344 m_outputLen += buflen;
345 m_output[m_outputLen] = '\0';
348 * If there's a prompt string in the collected output, it must be at
349 * the very end. In order to quickly find out whether there is a prompt
350 * string, we check whether the last character of m_output is identical
351 * to the last character of the prompt string. Only if it is, we check
352 * for the full prompt string.
354 * Note: Using the regular expression here is most expensive, because
355 * it translates m_output to a QString each time.
357 * Note: It could nevertheless happen that a character sequence that is
358 * equal to the prompt string appears at the end of the output,
359 * although it is very, very unlikely (namely as part of a string that
360 * lingered in gdb's output buffer due to some timing/heavy load
361 * conditions for a very long time such that that buffer overflowed
362 * exactly at the end of the prompt string look-a-like).
364 int promptStart = -1;
365 if (m_output[m_outputLen-1] == m_promptLastChar &&
366 m_outputLen >= m_promptMinLen)
368 // this is a candidate for a prompt at the end,
369 // now see if there really is
370 if (m_prompt[0] != '\0') {
371 if (strncmp(m_output+m_outputLen-m_promptMinLen,
372 m_prompt, m_promptMinLen) == 0)
374 promptStart = m_outputLen-m_promptMinLen;
376 } else {
377 QString output = QString::fromLatin1(m_output, m_outputLen);
378 #if QT_VERSION >= 300
379 promptStart = m_promptRE.search(output);
380 #else
381 promptStart = m_promptRE.match(output);
382 #endif
385 if (promptStart >= 0)
387 // found prompt!
389 // terminate output before the prompt
390 m_output[promptStart] = '\0';
393 * We've got output for the active command. But if it was
394 * interrupted, ignore it.
396 if (m_state != DSinterrupted) {
398 * m_state shouldn't be DSidle while we are parsing the output
399 * so that all commands produced by parse() go into the queue
400 * instead of being written to gdb immediately.
402 ASSERT(m_state != DSidle);
403 CmdQueueItem* cmd = m_activeCmd;
404 m_activeCmd = 0;
405 commandFinished(cmd);
406 delete cmd;
409 // empty buffer
410 m_outputLen = 0;
411 *m_output = '\0';
412 // also clear delayed output if interrupted
413 if (m_state == DSinterrupted) {
414 DelayedStr* delayed;
415 while ((delayed = m_delayedOutput.dequeue()) != 0) {
416 delete delayed;
421 * We parsed some output successfully. Unless there's more delayed
422 * output, the debugger must be idle now, so send down the next
423 * command.
425 if (m_delayedOutput.current() == 0) {
426 if (m_hipriCmdQueue.isEmpty() && m_lopriCmdQueue.isEmpty()) {
427 // no pending commands
428 m_state = DSidle;
429 emit enterIdleState();
430 } else {
431 writeCommand();
437 void DebuggerDriver::dequeueCmdByVar(VarTree* var)
439 if (var == 0)
440 return;
443 * Check the low-priority queue: We start at the back end, but skip the
444 * last element for now. The reason is that if we delete an element the
445 * current element is stepped to the next one - except if it's on the
446 * last: then it's stepped to the previous element. By checking the
447 * last element separately we avoid that special case.
449 CmdQueueItem* cmd = m_lopriCmdQueue.last();
450 while ((cmd = m_lopriCmdQueue.prev()) != 0) {
451 if (cmd->m_expr != 0 && var->isAncestorEq(cmd->m_expr)) {
452 // this is indeed a critical command; delete it
453 TRACE("removing critical lopri-cmd: " + cmd->m_cmdString);
454 m_lopriCmdQueue.remove(); /* steps to next element */
457 cmd = m_lopriCmdQueue.last();
458 if (cmd != 0) {
459 if (cmd->m_expr != 0 && var->isAncestorEq(cmd->m_expr)) {
460 TRACE("removing critical lopri-cmd: " + cmd->m_cmdString);
461 m_lopriCmdQueue.remove(); /* steps to next element */
467 QString DebuggerDriver::editableValue(VarTree* value)
469 // by default, let the user edit what is visible
470 return value->value();
474 StackFrame::~StackFrame()
476 delete var;
480 DbgAddr::DbgAddr(const QString& aa) :
481 a(aa)
483 cleanAddr();
487 * We strip off the leading 0x and any leading zeros.
489 void DbgAddr::cleanAddr()
491 if (a.isEmpty())
492 return;
494 while (a[0] == '0' || a[0] == 'x') {
495 a.remove(0, 1);
499 void DbgAddr::operator=(const QString& aa)
501 a = aa;
502 fnoffs = QString();
503 cleanAddr();
506 /* Re-attach 0x in front of the address */
507 QString DbgAddr::asString() const
509 if (a.isEmpty())
510 return QString();
511 else
512 return "0x" + a;
515 bool operator==(const DbgAddr& a1, const DbgAddr& a2)
517 return QString::compare(a1.a, a2.a) == 0;
520 bool operator>(const DbgAddr& a1, const DbgAddr& a2)
522 if (a1.a.length() > a2.a.length())
523 return true;
524 if (a1.a.length() < a2.a.length())
525 return false;
526 return QString::compare(a1.a, a2.a) > 0;
530 Breakpoint::Breakpoint() :
531 id(0),
532 type(breakpoint),
533 temporary(false),
534 enabled(true),
535 ignoreCount(0),
536 hitCount(0),
537 lineNo(0)
540 #include "dbgdriver.moc"