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.
11 #include <stdlib.h> /* strtol, atoi */
19 DebuggerDriver::DebuggerDriver() :
27 m_promptLastChar('\0')
30 m_output
= new char[m_outputAlloc
];
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);
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()
51 int DebuggerDriver::commSetupDoneC()
53 TRACE(__PRETTY_FUNCTION__
);
55 if (!KProcess::commSetupDoneC())
59 return dup2(STDOUT_FILENO
, STDERR_FILENO
) != -1;
62 static void splitCmdStr(const QString
& cmd
, ValArray
<QString
>& parts
)
64 QString str
= cmd
.simplifyWhiteSpace();
67 while ((end
= str
.find(' ', start
)) >= 0) {
68 parts
.append(str
.mid(start
, end
-start
));
71 parts
.append(str
.mid(start
, str
.length()-start
));
75 bool DebuggerDriver::startup(QString cmdStr
)
77 // clear command queues
80 m_hipriCmdQueue
.clear();
81 bool autodel
= m_lopriCmdQueue
.autoDelete();
82 m_lopriCmdQueue
.setAutoDelete(true);
83 m_lopriCmdQueue
.clear();
84 m_lopriCmdQueue
.setAutoDelete(autodel
);
87 // debugger executable
89 cmdStr
= defaultInvocation();
91 ValArray
<QString
> cmd
;
92 splitCmdStr(cmdStr
, cmd
);
94 for (int i
= 0; i
< cmd
.size(); i
++) {
98 if (!start(KProcess::NotifyOnExit
,
99 KProcess::Communication(KProcess::Stdin
|KProcess::Stdout
))) {
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());
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);
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
);
143 if (m_state
== DSrunningLow
) {
144 // take the liberty to interrupt the running command
145 m_state
= DSinterrupted
;
147 ASSERT(m_activeCmd
!= 0);
148 TRACE(QString().sprintf("interrupted the command %d",
149 (m_activeCmd
? m_activeCmd
->m_cmd
: -1)));
155 // if gdb is idle, send it the command
156 if (m_state
== DSidle
) {
157 ASSERT(m_activeCmd
== 0);
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;
170 case QMoverrideMoreEqual
:
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
)
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
)
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
);
192 } // else none found, so add it
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);
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
;
219 cmd
= m_lopriCmdQueue
.first();
220 m_lopriCmdQueue
.removeFirst();
221 newState
= DScommandSentLow
;
225 m_state
= DSidle
; /* is necessary if command was interrupted earlier */
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());
244 void DebuggerDriver::flushLoPriQueue()
246 while (!m_lopriCmdQueue
.isEmpty()) {
247 delete m_lopriCmdQueue
.take(0);
251 void DebuggerDriver::flushHiPriQueue()
254 while ((cmd
= m_hipriCmdQueue
.dequeue()) != 0) {
259 void DebuggerDriver::flushCommands(bool hipriOnly
)
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();
291 // re-receive delayed output
292 if (m_delayedOutput
.current() != 0) {
294 while ((delayed
= m_delayedOutput
.dequeue()) != 0) {
295 const char* str
= delayed
->data();
296 slotReceiveOutput(0, const_cast<char*>(str
), delayed
->length());
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));
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
);
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
) {
335 TRACE("ignoring stray output: " + DelayedStr(buffer
, buflen
+1));
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
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
);
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
;
390 QString output
= QString::fromLatin1(m_output
, m_outputLen
);
391 #if QT_VERSION >= 300
392 promptStart
= m_promptRE
.search(output
);
394 promptStart
= m_promptRE
.match(output
);
398 if (promptStart
>= 0)
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
;
418 commandFinished(cmd
);
425 // also clear delayed output if interrupted
426 if (m_state
== DSinterrupted
) {
428 while ((delayed
= m_delayedOutput
.dequeue()) != 0) {
434 * We parsed some output successfully. Unless there's more delayed
435 * output, the debugger must be idle now, so send down the next
438 if (m_delayedOutput
.current() == 0) {
439 if (m_hipriCmdQueue
.isEmpty() && m_lopriCmdQueue
.isEmpty()) {
440 // no pending commands
442 emit
enterIdleState();
450 void DebuggerDriver::dequeueCmdByVar(VarTree
* var
)
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();
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()
493 DbgAddr::DbgAddr(const QString
& aa
) :
500 * We strip off the leading 0x and any leading zeros.
502 void DbgAddr::cleanAddr()
507 while (a
[0] == '0' || a
[0] == 'x') {
512 void DbgAddr::operator=(const QString
& aa
)
519 /* Re-attach 0x in front of the address */
520 QString
DbgAddr::asString() const
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())
537 if (a1
.a
.length() < a2
.a
.length())
539 return QString::compare(a1
.a
, a2
.a
) > 0;
543 Breakpoint::Breakpoint() :
553 #include "dbgdriver.moc"