3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
10 #include <stdlib.h> /* strtol, atoi */
17 DebuggerDriver::DebuggerDriver() :
28 m_output
= new char[m_outputAlloc
];
33 m_hipriCmdQueue
.setAutoDelete(true);
36 connect(this, SIGNAL(receivedStdout(KProcess
*,char*,int)),
37 SLOT(slotReceiveOutput(KProcess
*,char*,int)));
38 connect(this, SIGNAL(wroteStdin(KProcess
*)), SLOT(slotCommandRead(KProcess
*)));
39 connect(this, SIGNAL(processExited(KProcess
*)), SLOT(slotExited(KProcess
*)));
42 DebuggerDriver::~DebuggerDriver()
47 int DebuggerDriver::commSetupDoneC()
49 TRACE(__PRETTY_FUNCTION__
);
51 if (!KProcess::commSetupDoneC())
55 return dup2(STDOUT_FILENO
, STDERR_FILENO
) != -1;
58 static void splitCmdStr(const QString
& cmd
, ValArray
<QString
>& parts
)
60 QString str
= cmd
.simplifyWhiteSpace();
63 while ((end
= str
.find(' ', start
)) >= 0) {
64 parts
.append(str
.mid(start
, end
-start
));
67 parts
.append(str
.mid(start
, str
.length()-start
));
71 bool DebuggerDriver::startup(QString cmdStr
)
73 // clear command queues
76 m_hipriCmdQueue
.clear();
77 bool autodel
= m_lopriCmdQueue
.autoDelete();
78 m_lopriCmdQueue
.setAutoDelete(true);
79 m_lopriCmdQueue
.clear();
80 m_lopriCmdQueue
.setAutoDelete(autodel
);
83 // debugger executable
85 cmdStr
= defaultInvocation();
87 ValArray
<QString
> cmd
;
88 splitCmdStr(cmdStr
, cmd
);
90 for (int i
= 0; i
< cmd
.size(); i
++) {
94 if (!start(KProcess::NotifyOnExit
,
95 KProcess::Communication(KProcess::Stdin
|KProcess::Stdout
))) {
100 if (!m_logFile
.isOpen() && !m_logFileName
.isEmpty()) {
101 m_logFile
.setName(m_logFileName
);
102 m_logFile
.open(IO_WriteOnly
);
108 void DebuggerDriver::slotExited(KProcess
*)
110 static const char txt
[] = "\n====== debugger exited ======\n";
111 if (m_logFile
.isOpen()) {
112 m_logFile
.writeBlock(txt
,sizeof(txt
)-1);
123 CmdQueueItem
* DebuggerDriver::executeCmdString(DbgCommand cmd
,
124 QString cmdString
, bool clearLow
)
126 // place a new command into the high-priority queue
127 CmdQueueItem
* cmdItem
= new CmdQueueItem(cmd
, cmdString
);
128 m_hipriCmdQueue
.enqueue(cmdItem
);
131 if (m_state
== DSrunningLow
) {
132 // take the liberty to interrupt the running command
133 m_state
= DSinterrupted
;
135 ASSERT(m_activeCmd
!= 0);
136 TRACE(QString().sprintf("interrupted the command %d",
137 (m_activeCmd
? m_activeCmd
->m_cmd
: -1)));
143 // if gdb is idle, send it the command
144 if (m_state
== DSidle
) {
145 ASSERT(m_activeCmd
== 0);
152 CmdQueueItem
* DebuggerDriver::queueCmdString(DbgCommand cmd
,
153 QString cmdString
, QueueMode mode
)
155 // place a new command into the low-priority queue
156 CmdQueueItem
* cmdItem
= 0;
158 case QMoverrideMoreEqual
:
160 // check whether gdb is currently processing this command
161 if (m_activeCmd
!= 0 &&
162 m_activeCmd
->m_cmd
== cmd
&& m_activeCmd
->m_cmdString
== cmdString
)
166 // check whether there is already the same command in the queue
167 for (cmdItem
= m_lopriCmdQueue
.first(); cmdItem
!= 0; cmdItem
= m_lopriCmdQueue
.next()) {
168 if (cmdItem
->m_cmd
== cmd
&& cmdItem
->m_cmdString
== cmdString
)
173 if (mode
== QMoverrideMoreEqual
) {
174 // All commands are equal, but some are more equal than others...
175 // put this command in front of all others
176 m_lopriCmdQueue
.take();
177 m_lopriCmdQueue
.insert(0, cmdItem
);
180 } // else none found, so add it
183 cmdItem
= new CmdQueueItem(cmd
, cmdString
);
184 m_lopriCmdQueue
.append(cmdItem
);
187 // if gdb is idle, send it the command
188 if (m_state
== DSidle
) {
189 ASSERT(m_activeCmd
== 0);
196 // dequeue a pending command, make it the active one and send it to gdb
197 void DebuggerDriver::writeCommand()
199 // ASSERT(m_activeCmd == 0);
200 assert(m_activeCmd
== 0);
202 // first check the high-priority queue - only if it is empty
203 // use a low-priority command.
204 CmdQueueItem
* cmd
= m_hipriCmdQueue
.dequeue();
205 DebuggerState newState
= DScommandSent
;
207 cmd
= m_lopriCmdQueue
.first();
208 m_lopriCmdQueue
.removeFirst();
209 newState
= DScommandSentLow
;
213 m_state
= DSidle
; /* is necessary if command was interrupted earlier */
218 TRACE("in writeCommand: " + cmd
->m_cmdString
);
220 const char* str
= cmd
->m_cmdString
;
221 writeStdin(const_cast<char*>(str
), cmd
->m_cmdString
.length());
223 // write also to log file
224 if (m_logFile
.isOpen()) {
225 m_logFile
.writeBlock(str
, cmd
->m_cmdString
.length());
232 void DebuggerDriver::flushLoPriQueue()
234 while (!m_lopriCmdQueue
.isEmpty()) {
235 delete m_lopriCmdQueue
.take(0);
239 void DebuggerDriver::flushHiPriQueue()
242 while ((cmd
= m_hipriCmdQueue
.dequeue()) != 0) {
247 void DebuggerDriver::flushCommands(bool hipriOnly
)
255 void DebuggerDriver::slotCommandRead(KProcess
*)
257 TRACE(__PRETTY_FUNCTION__
);
259 // there must be an active command which is not yet commited
260 ASSERT(m_state
== DScommandSent
|| m_state
== DScommandSentLow
);
261 ASSERT(m_activeCmd
!= 0);
262 ASSERT(!m_activeCmd
->m_committed
);
264 // commit the command
265 m_activeCmd
->m_committed
= true;
267 // now the debugger is officially working on the command
268 m_state
= m_state
== DScommandSent
? DSrunning
: DSrunningLow
;
270 // set the flag that reflects whether the program is really running
271 switch (m_activeCmd
->m_cmd
) {
272 case DCrun
: case DCcont
: case DCnext
: case DCstep
: case DCfinish
: case DCuntil
:
273 emit
inferiorRunning();
279 // re-receive delayed output
280 if (m_delayedOutput
.current() != 0) {
282 while ((delayed
= m_delayedOutput
.dequeue()) != 0) {
283 const char* str
= delayed
->data();
284 slotReceiveOutput(0, const_cast<char*>(str
), delayed
->length());
290 void DebuggerDriver::slotReceiveOutput(KProcess
*, char* buffer
, int buflen
)
293 * The debugger should be running (processing a command) at this point.
294 * If it is not, it is still idle because we haven't received the
295 * wroteStdin signal yet, in which case there must be an active command
296 * which is not commited.
298 if (m_state
== DScommandSent
|| m_state
== DScommandSentLow
) {
299 ASSERT(m_activeCmd
!= 0);
300 ASSERT(!m_activeCmd
->m_committed
);
302 * We received output before we got signal wroteStdin. Collect this
303 * output, it will be re-sent by commandRead when it gets the
304 * acknowledgment for the uncommitted command.
306 m_delayedOutput
.enqueue(new DelayedStr(buffer
, buflen
+1));
309 // write to log file (do not log delayed output - it would appear twice)
310 if (m_logFile
.isOpen()) {
311 m_logFile
.writeBlock(buffer
, buflen
);
316 * gdb sometimes produces stray output while it's idle. This happens if
317 * it receives a signal, most prominently a SIGCONT after a SIGTSTP:
318 * The user haltet kdbg with Ctrl-Z, then continues it with "fg", which
319 * also continues gdb, which repeats the prompt!
321 if (m_activeCmd
== 0 && m_state
!= DSinterrupted
) {
323 TRACE("ignoring stray output: " + DelayedStr(buffer
, buflen
+1));
326 ASSERT(m_state
== DSrunning
|| m_state
== DSrunningLow
|| m_state
== DSinterrupted
);
327 ASSERT(m_activeCmd
!= 0 || m_state
== DSinterrupted
);
329 // collect output until next prompt string is found
332 if (m_outputLen
+ buflen
>= m_outputAlloc
) {
334 * Must enlarge m_output: double it. Note: That particular
335 * sequence of commandes here ensures exception safety.
337 int newSize
= m_outputAlloc
* 2;
338 char* newBuf
= new char[newSize
];
339 memcpy(newBuf
, m_output
, m_outputLen
);
342 m_outputAlloc
= newSize
;
344 memcpy(m_output
+m_outputLen
, buffer
, buflen
);
345 m_outputLen
+= buflen
;
346 m_output
[m_outputLen
] = '\0';
349 * If there's a prompt string in the collected output, it must be at
352 * Note: It could nevertheless happen that a character sequence that is
353 * equal to the prompt string appears at the end of the output,
354 * although it is very, very unlikely (namely as part of a string that
355 * lingered in gdb's output buffer due to some timing/heavy load
356 * conditions for a very long time such that that buffer overflowed
357 * exactly at the end of the prompt string look-a-like).
359 if (m_output
[m_outputLen
-1] == m_promptLastChar
&&
360 m_outputLen
>= m_promptLen
&&
361 strncmp(m_output
+m_outputLen
-m_promptLen
, m_prompt
, m_promptLen
) == 0)
365 // terminate output before the prompt
366 m_output
[m_outputLen
-m_promptLen
] = '\0';
369 * We've got output for the active command. But if it was
370 * interrupted, ignore it.
372 if (m_state
!= DSinterrupted
) {
374 * m_state shouldn't be DSidle while we are parsing the output
375 * so that all commands produced by parse() go into the queue
376 * instead of being written to gdb immediately.
378 ASSERT(m_state
!= DSidle
);
379 CmdQueueItem
* cmd
= m_activeCmd
;
381 commandFinished(cmd
);
388 // also clear delayed output if interrupted
389 if (m_state
== DSinterrupted
) {
391 while ((delayed
= m_delayedOutput
.dequeue()) != 0) {
397 * We parsed some output successfully. Unless there's more delayed
398 * output, the debugger must be idle now, so send down the next
401 if (m_delayedOutput
.current() == 0) {
402 if (m_hipriCmdQueue
.isEmpty() && m_lopriCmdQueue
.isEmpty()) {
403 // no pending commands
405 emit
enterIdleState();
413 void DebuggerDriver::dequeueCmdByVar(VarTree
* var
)
419 * Check the low-priority queue: We start at the back end, but skip the
420 * last element for now. The reason is that if we delete an element the
421 * current element is stepped to the next one - except if it's on the
422 * last: then it's stepped to the previous element. By checking the
423 * last element separately we avoid that special case.
425 CmdQueueItem
* cmd
= m_lopriCmdQueue
.last();
426 while ((cmd
= m_lopriCmdQueue
.prev()) != 0) {
427 if (cmd
->m_expr
!= 0 && var
->isAncestorEq(cmd
->m_expr
)) {
428 // this is indeed a critical command; delete it
429 TRACE("removing critical lopri-cmd: " + cmd
->m_cmdString
);
430 m_lopriCmdQueue
.remove(); /* steps to next element */
433 cmd
= m_lopriCmdQueue
.last();
435 if (cmd
->m_expr
!= 0 && var
->isAncestorEq(cmd
->m_expr
)) {
436 TRACE("removing critical lopri-cmd: " + cmd
->m_cmdString
);
437 m_lopriCmdQueue
.remove(); /* steps to next element */
442 StackFrame::~StackFrame()
448 DbgAddr::DbgAddr(const QString
& aa
) :
455 * We strip off the leading 0x and any leading zeros.
457 void DbgAddr::cleanAddr()
462 while (a
[0] == '0' || a
[0] == 'x') {
467 void DbgAddr::operator=(const QString
& aa
)
474 /* Re-attach 0x in front of the address */
475 QString
DbgAddr::asString() const
483 bool operator==(const DbgAddr
& a1
, const DbgAddr
& a2
)
486 return strcmp(a1
.a
, a2
.a
) == 0;
488 return QString::compare(a1
.a
, a2
.a
) == 0;
492 bool operator>(const DbgAddr
& a1
, const DbgAddr
& a2
)
494 if (a1
.a
.length() > a2
.a
.length())
496 if (a1
.a
.length() < a2
.a
.length())
499 return strcmp(a1
.a
, a2
.a
) > 0;
501 return QString::compare(a1
.a
, a2
.a
) > 0;
506 #include "dbgdriver.moc"