Merge branch 'maint'
[kdbg.git] / kdbg / dbgdriver.cpp
blobec5a90b80fdf6b52c248cd66bb62dd7d812f2900
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 "valarray.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;
62 static void splitCmdStr(const QString& cmd, ValArray<QString>& parts)
64 QString str = cmd.simplifyWhiteSpace();
65 int start = 0;
66 int end;
67 while ((end = str.find(' ', start)) >= 0) {
68 parts.append(str.mid(start, end-start));
69 start = end+1;
71 parts.append(str.mid(start, str.length()-start));
75 bool DebuggerDriver::startup(QString cmdStr)
77 // clear command queues
78 delete m_activeCmd;
79 m_activeCmd = 0;
80 m_hipriCmdQueue.clear();
81 bool autodel = m_lopriCmdQueue.autoDelete();
82 m_lopriCmdQueue.setAutoDelete(true);
83 m_lopriCmdQueue.clear();
84 m_lopriCmdQueue.setAutoDelete(autodel);
85 m_state = DSidle;
87 // debugger executable
88 if (cmdStr.isEmpty())
89 cmdStr = defaultInvocation();
91 ValArray<QString> cmd;
92 splitCmdStr(cmdStr, cmd);
93 clearArguments();
94 for (int i = 0; i < cmd.size(); i++) {
95 *this << cmd[i];
98 if (!start(KProcess::NotifyOnExit,
99 KProcess::Communication(KProcess::Stdin|KProcess::Stdout))) {
100 return false;
103 // open log file
104 if (!m_logFile.isOpen() && !m_logFileName.isEmpty()) {
105 m_logFile.setName(m_logFileName);
106 m_logFile.open(IO_WriteOnly);
109 // these must be set by derived classes in their constructor
110 assert(m_promptMinLen > 0); // _must_ have a prompt
111 assert(m_promptLastChar != '\0'); // last char _must_ be fixed
112 assert(m_prompt[0] == '\0' || strlen(m_prompt) == m_promptMinLen);
113 // either a prompt or a regexp
114 assert(m_prompt[0] != '\0' && m_promptMinLen < sizeof(m_prompt) ||
115 !m_promptRE.isEmpty() && m_promptRE.isValid());
117 return true;
120 void DebuggerDriver::slotExited(KProcess*)
122 static const char txt[] = "\n====== debugger exited ======\n";
123 if (m_logFile.isOpen()) {
124 m_logFile.writeBlock(txt,sizeof(txt)-1);
127 // reset state
128 m_state = DSidle;
129 // empty buffer
130 m_outputLen = 0;
131 *m_output = '\0';
135 CmdQueueItem* DebuggerDriver::executeCmdString(DbgCommand cmd,
136 QString cmdString, bool clearLow)
138 // place a new command into the high-priority queue
139 CmdQueueItem* cmdItem = new CmdQueueItem(cmd, cmdString);
140 m_hipriCmdQueue.enqueue(cmdItem);
142 if (clearLow) {
143 if (m_state == DSrunningLow) {
144 // take the liberty to interrupt the running command
145 m_state = DSinterrupted;
146 kill(SIGINT);
147 ASSERT(m_activeCmd != 0);
148 TRACE(QString().sprintf("interrupted the command %d",
149 (m_activeCmd ? m_activeCmd->m_cmd : -1)));
150 delete m_activeCmd;
151 m_activeCmd = 0;
153 flushLoPriQueue();
155 // if gdb is idle, send it the command
156 if (m_state == DSidle) {
157 ASSERT(m_activeCmd == 0);
158 writeCommand();
161 return cmdItem;
164 CmdQueueItem* DebuggerDriver::queueCmdString(DbgCommand cmd,
165 QString cmdString, QueueMode mode)
167 // place a new command into the low-priority queue
168 CmdQueueItem* cmdItem = 0;
169 switch (mode) {
170 case QMoverrideMoreEqual:
171 case QMoverride:
172 // check whether gdb is currently processing this command
173 if (m_activeCmd != 0 &&
174 m_activeCmd->m_cmd == cmd && m_activeCmd->m_cmdString == cmdString)
176 return m_activeCmd;
178 // check whether there is already the same command in the queue
179 for (cmdItem = m_lopriCmdQueue.first(); cmdItem != 0; cmdItem = m_lopriCmdQueue.next()) {
180 if (cmdItem->m_cmd == cmd && cmdItem->m_cmdString == cmdString)
181 break;
183 if (cmdItem != 0) {
184 // found one
185 if (mode == QMoverrideMoreEqual) {
186 // All commands are equal, but some are more equal than others...
187 // put this command in front of all others
188 m_lopriCmdQueue.take();
189 m_lopriCmdQueue.insert(0, cmdItem);
191 break;
192 } // else none found, so add it
193 // drop through
194 case QMnormal:
195 cmdItem = new CmdQueueItem(cmd, cmdString);
196 m_lopriCmdQueue.append(cmdItem);
199 // if gdb is idle, send it the command
200 if (m_state == DSidle) {
201 ASSERT(m_activeCmd == 0);
202 writeCommand();
205 return cmdItem;
208 // dequeue a pending command, make it the active one and send it to gdb
209 void DebuggerDriver::writeCommand()
211 // ASSERT(m_activeCmd == 0);
212 assert(m_activeCmd == 0);
214 // first check the high-priority queue - only if it is empty
215 // use a low-priority command.
216 CmdQueueItem* cmd = m_hipriCmdQueue.dequeue();
217 DebuggerState newState = DScommandSent;
218 if (cmd == 0) {
219 cmd = m_lopriCmdQueue.first();
220 m_lopriCmdQueue.removeFirst();
221 newState = DScommandSentLow;
223 if (cmd == 0) {
224 // nothing to do
225 m_state = DSidle; /* is necessary if command was interrupted earlier */
226 return;
229 m_activeCmd = cmd;
230 TRACE("in writeCommand: " + cmd->m_cmdString);
232 const char* str = cmd->m_cmdString;
233 writeStdin(const_cast<char*>(str), cmd->m_cmdString.length());
235 // write also to log file
236 if (m_logFile.isOpen()) {
237 m_logFile.writeBlock(str, cmd->m_cmdString.length());
238 m_logFile.flush();
241 m_state = newState;
244 void DebuggerDriver::flushLoPriQueue()
246 while (!m_lopriCmdQueue.isEmpty()) {
247 delete m_lopriCmdQueue.take(0);
251 void DebuggerDriver::flushHiPriQueue()
253 CmdQueueItem* cmd;
254 while ((cmd = m_hipriCmdQueue.dequeue()) != 0) {
255 delete cmd;
259 void DebuggerDriver::flushCommands(bool hipriOnly)
261 flushHiPriQueue();
262 if (!hipriOnly) {
263 flushLoPriQueue();
267 void DebuggerDriver::slotCommandRead(KProcess*)
269 TRACE(__PRETTY_FUNCTION__);
271 // there must be an active command which is not yet commited
272 ASSERT(m_state == DScommandSent || m_state == DScommandSentLow);
273 ASSERT(m_activeCmd != 0);
274 ASSERT(!m_activeCmd->m_committed);
276 // commit the command
277 m_activeCmd->m_committed = true;
279 // now the debugger is officially working on the command
280 m_state = m_state == DScommandSent ? DSrunning : DSrunningLow;
282 // set the flag that reflects whether the program is really running
283 switch (m_activeCmd->m_cmd) {
284 case DCrun: case DCcont: case DCnext: case DCstep: case DCfinish: case DCuntil:
285 emit inferiorRunning();
286 break;
287 default:
288 break;
291 // re-receive delayed output
292 if (m_delayedOutput.current() != 0) {
293 DelayedStr* delayed;
294 while ((delayed = m_delayedOutput.dequeue()) != 0) {
295 const char* str = delayed->data();
296 slotReceiveOutput(0, const_cast<char*>(str), delayed->length());
297 delete delayed;
302 void DebuggerDriver::slotReceiveOutput(KProcess*, char* buffer, int buflen)
305 * The debugger should be running (processing a command) at this point.
306 * If it is not, it is still idle because we haven't received the
307 * wroteStdin signal yet, in which case there must be an active command
308 * which is not commited.
310 if (m_state == DScommandSent || m_state == DScommandSentLow) {
311 ASSERT(m_activeCmd != 0);
312 ASSERT(!m_activeCmd->m_committed);
314 * We received output before we got signal wroteStdin. Collect this
315 * output, it will be re-sent by commandRead when it gets the
316 * acknowledgment for the uncommitted command.
318 m_delayedOutput.enqueue(new DelayedStr(buffer, buflen+1));
319 return;
321 // write to log file (do not log delayed output - it would appear twice)
322 if (m_logFile.isOpen()) {
323 m_logFile.writeBlock(buffer, buflen);
324 m_logFile.flush();
328 * gdb sometimes produces stray output while it's idle. This happens if
329 * it receives a signal, most prominently a SIGCONT after a SIGTSTP:
330 * The user haltet kdbg with Ctrl-Z, then continues it with "fg", which
331 * also continues gdb, which repeats the prompt!
333 if (m_activeCmd == 0 && m_state != DSinterrupted) {
334 // ignore the output
335 TRACE("ignoring stray output: " + DelayedStr(buffer, buflen+1));
336 return;
338 ASSERT(m_state == DSrunning || m_state == DSrunningLow || m_state == DSinterrupted);
339 ASSERT(m_activeCmd != 0 || m_state == DSinterrupted);
341 // collect output until next prompt string is found
343 // accumulate it
344 if (m_outputLen + buflen >= m_outputAlloc) {
346 * Must enlarge m_output: double it. Note: That particular
347 * sequence of commandes here ensures exception safety.
349 int newSize = m_outputAlloc * 2;
350 char* newBuf = new char[newSize];
351 memcpy(newBuf, m_output, m_outputLen);
352 delete[] m_output;
353 m_output = newBuf;
354 m_outputAlloc = newSize;
356 memcpy(m_output+m_outputLen, buffer, buflen);
357 m_outputLen += buflen;
358 m_output[m_outputLen] = '\0';
361 * If there's a prompt string in the collected output, it must be at
362 * the very end. In order to quickly find out whether there is a prompt
363 * string, we check whether the last character of m_output is identical
364 * to the last character of the prompt string. Only if it is, we check
365 * for the full prompt string.
367 * Note: Using the regular expression here is most expensive, because
368 * it translates m_output to a QString each time.
370 * Note: It could nevertheless happen that a character sequence that is
371 * equal to the prompt string appears at the end of the output,
372 * although it is very, very unlikely (namely as part of a string that
373 * lingered in gdb's output buffer due to some timing/heavy load
374 * conditions for a very long time such that that buffer overflowed
375 * exactly at the end of the prompt string look-a-like).
377 int promptStart = -1;
378 if (m_output[m_outputLen-1] == m_promptLastChar &&
379 m_outputLen >= m_promptMinLen)
381 // this is a candidate for a prompt at the end,
382 // now see if there really is
383 if (m_prompt[0] != '\0') {
384 if (strncmp(m_output+m_outputLen-m_promptMinLen,
385 m_prompt, m_promptMinLen) == 0)
387 promptStart = m_outputLen-m_promptMinLen;
389 } else {
390 QString output = QString::fromLatin1(m_output, m_outputLen);
391 #if QT_VERSION >= 300
392 promptStart = m_promptRE.search(output);
393 #else
394 promptStart = m_promptRE.match(output);
395 #endif
398 if (promptStart >= 0)
400 // found prompt!
402 // terminate output before the prompt
403 m_output[promptStart] = '\0';
406 * We've got output for the active command. But if it was
407 * interrupted, ignore it.
409 if (m_state != DSinterrupted) {
411 * m_state shouldn't be DSidle while we are parsing the output
412 * so that all commands produced by parse() go into the queue
413 * instead of being written to gdb immediately.
415 ASSERT(m_state != DSidle);
416 CmdQueueItem* cmd = m_activeCmd;
417 m_activeCmd = 0;
418 commandFinished(cmd);
419 delete cmd;
422 // empty buffer
423 m_outputLen = 0;
424 *m_output = '\0';
425 // also clear delayed output if interrupted
426 if (m_state == DSinterrupted) {
427 DelayedStr* delayed;
428 while ((delayed = m_delayedOutput.dequeue()) != 0) {
429 delete delayed;
434 * We parsed some output successfully. Unless there's more delayed
435 * output, the debugger must be idle now, so send down the next
436 * command.
438 if (m_delayedOutput.current() == 0) {
439 if (m_hipriCmdQueue.isEmpty() && m_lopriCmdQueue.isEmpty()) {
440 // no pending commands
441 m_state = DSidle;
442 emit enterIdleState();
443 } else {
444 writeCommand();
450 void DebuggerDriver::dequeueCmdByVar(VarTree* var)
452 if (var == 0)
453 return;
456 * Check the low-priority queue: We start at the back end, but skip the
457 * last element for now. The reason is that if we delete an element the
458 * current element is stepped to the next one - except if it's on the
459 * last: then it's stepped to the previous element. By checking the
460 * last element separately we avoid that special case.
462 CmdQueueItem* cmd = m_lopriCmdQueue.last();
463 while ((cmd = m_lopriCmdQueue.prev()) != 0) {
464 if (cmd->m_expr != 0 && var->isAncestorEq(cmd->m_expr)) {
465 // this is indeed a critical command; delete it
466 TRACE("removing critical lopri-cmd: " + cmd->m_cmdString);
467 m_lopriCmdQueue.remove(); /* steps to next element */
470 cmd = m_lopriCmdQueue.last();
471 if (cmd != 0) {
472 if (cmd->m_expr != 0 && var->isAncestorEq(cmd->m_expr)) {
473 TRACE("removing critical lopri-cmd: " + cmd->m_cmdString);
474 m_lopriCmdQueue.remove(); /* steps to next element */
480 QString DebuggerDriver::editableValue(VarTree* value)
482 // by default, let the user edit what is visible
483 return value->value();
487 StackFrame::~StackFrame()
489 delete var;
493 DbgAddr::DbgAddr(const QString& aa) :
494 a(aa)
496 cleanAddr();
500 * We strip off the leading 0x and any leading zeros.
502 void DbgAddr::cleanAddr()
504 if (a.isEmpty())
505 return;
507 while (a[0] == '0' || a[0] == 'x') {
508 a.remove(0, 1);
512 void DbgAddr::operator=(const QString& aa)
514 a = aa;
515 fnoffs = QString();
516 cleanAddr();
519 /* Re-attach 0x in front of the address */
520 QString DbgAddr::asString() const
522 if (a.isEmpty())
523 return QString();
524 else
525 return "0x" + a;
528 bool operator==(const DbgAddr& a1, const DbgAddr& a2)
530 return QString::compare(a1.a, a2.a) == 0;
533 bool operator>(const DbgAddr& a1, const DbgAddr& a2)
535 if (a1.a.length() > a2.a.length())
536 return true;
537 if (a1.a.length() < a2.a.length())
538 return false;
539 return QString::compare(a1.a, a2.a) > 0;
543 Breakpoint::Breakpoint() :
544 id(0),
545 type(breakpoint),
546 temporary(false),
547 enabled(true),
548 ignoreCount(0),
549 hitCount(0),
550 lineNo(0)
553 #include "dbgdriver.moc"