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.
9 #include <qstringlist.h>
11 #include <stdlib.h> /* strtol, atoi */
17 DebuggerDriver::DebuggerDriver() :
26 m_output
= new char[m_outputAlloc
];
29 connect(this, SIGNAL(receivedStdout(K3Process
*,char*,int)),
30 SLOT(slotReceiveOutput(K3Process
*,char*,int)));
31 connect(this, SIGNAL(wroteStdin(K3Process
*)), SLOT(slotCommandRead(K3Process
*)));
32 connect(this, SIGNAL(processExited(K3Process
*)), SLOT(slotExited(K3Process
*)));
35 DebuggerDriver::~DebuggerDriver()
42 int DebuggerDriver::commSetupDoneC()
44 TRACE(__PRETTY_FUNCTION__
);
46 if (!K3Process::commSetupDoneC())
50 return dup2(STDOUT_FILENO
, STDERR_FILENO
) != -1;
54 bool DebuggerDriver::startup(QString cmdStr
)
56 // clear command queues
63 // debugger executable
65 cmdStr
= defaultInvocation();
67 QStringList cmd
= QStringList::split(' ', cmdStr
);
69 for (QStringList::iterator i
= cmd
.begin(); i
!= cmd
.end(); ++i
) {
73 if (!start(K3Process::NotifyOnExit
,
74 K3Process::Communication(K3Process::Stdin
|K3Process::Stdout
))) {
79 if (!m_logFile
.isOpen() && !m_logFileName
.isEmpty()) {
80 m_logFile
.setName(m_logFileName
);
81 m_logFile
.open(QIODevice::WriteOnly
);
87 void DebuggerDriver::slotExited(K3Process
*)
89 static const char txt
[] = "\n====== debugger exited ======\n";
90 if (m_logFile
.isOpen()) {
91 m_logFile
.writeBlock(txt
,sizeof(txt
)-1);
102 CmdQueueItem
* DebuggerDriver::executeCmdString(DbgCommand cmd
,
103 QString cmdString
, bool clearLow
)
105 // place a new command into the high-priority queue
106 CmdQueueItem
* cmdItem
= new CmdQueueItem(cmd
, cmdString
);
107 m_hipriCmdQueue
.push(cmdItem
);
110 if (m_state
== DSrunningLow
) {
111 // take the liberty to interrupt the running command
112 m_state
= DSinterrupted
;
114 ASSERT(m_activeCmd
!= 0);
115 TRACE(QString().sprintf("interrupted the command %d",
116 (m_activeCmd
? m_activeCmd
->m_cmd
: -1)));
122 // if gdb is idle, send it the command
123 if (m_state
== DSidle
) {
124 ASSERT(m_activeCmd
== 0);
131 bool CmdQueueItem::IsEqualCmd::operator()(CmdQueueItem
* cmd
) const
133 return cmd
->m_cmd
== m_cmd
&& cmd
->m_cmdString
== m_str
;
136 CmdQueueItem
* DebuggerDriver::queueCmdString(DbgCommand cmd
,
137 QString cmdString
, QueueMode mode
)
139 // place a new command into the low-priority queue
140 std::list
<CmdQueueItem
*>::iterator i
;
141 CmdQueueItem
* cmdItem
= 0;
143 case QMoverrideMoreEqual
:
145 // check whether gdb is currently processing this command
146 if (m_activeCmd
!= 0 &&
147 m_activeCmd
->m_cmd
== cmd
&& m_activeCmd
->m_cmdString
== cmdString
)
151 // check whether there is already the same command in the queue
152 i
= find_if(m_lopriCmdQueue
.begin(), m_lopriCmdQueue
.end(), CmdQueueItem::IsEqualCmd(cmd
, cmdString
));
153 if (i
!= m_lopriCmdQueue
.end()) {
156 if (mode
== QMoverrideMoreEqual
) {
157 // All commands are equal, but some are more equal than others...
158 // put this command in front of all others
159 m_lopriCmdQueue
.erase(i
);
160 m_lopriCmdQueue
.push_front(cmdItem
);
163 } // else none found, so add it
166 cmdItem
= new CmdQueueItem(cmd
, cmdString
);
167 m_lopriCmdQueue
.push_back(cmdItem
);
170 // if gdb is idle, send it the command
171 if (m_state
== DSidle
) {
172 ASSERT(m_activeCmd
== 0);
179 // dequeue a pending command, make it the active one and send it to gdb
180 void DebuggerDriver::writeCommand()
182 // ASSERT(m_activeCmd == 0);
183 assert(m_activeCmd
== 0);
185 // first check the high-priority queue - only if it is empty
186 // use a low-priority command.
188 DebuggerState newState
= DScommandSent
;
189 if (!m_hipriCmdQueue
.empty()) {
190 cmd
= m_hipriCmdQueue
.front();
191 m_hipriCmdQueue
.pop();
192 } else if (!m_lopriCmdQueue
.empty()) {
193 cmd
= m_lopriCmdQueue
.front();
194 m_lopriCmdQueue
.pop_front();
195 newState
= DScommandSentLow
;
198 m_state
= DSidle
; /* is necessary if command was interrupted earlier */
203 TRACE("in writeCommand: " + cmd
->m_cmdString
);
205 const char* str
= cmd
->m_cmdString
;
206 writeStdin(const_cast<char*>(str
), cmd
->m_cmdString
.length());
208 // write also to log file
209 if (m_logFile
.isOpen()) {
210 m_logFile
.writeBlock(str
, cmd
->m_cmdString
.length());
217 void DebuggerDriver::flushLoPriQueue()
219 while (!m_lopriCmdQueue
.empty()) {
220 delete m_lopriCmdQueue
.back();
221 m_lopriCmdQueue
.pop_back();
225 void DebuggerDriver::flushHiPriQueue()
227 while (!m_hipriCmdQueue
.empty()) {
228 delete m_hipriCmdQueue
.front();
229 m_hipriCmdQueue
.pop();
233 void DebuggerDriver::flushCommands(bool hipriOnly
)
241 void DebuggerDriver::slotCommandRead(K3Process
*)
243 TRACE(__PRETTY_FUNCTION__
);
245 // there must be an active command which is not yet commited
246 ASSERT(m_state
== DScommandSent
|| m_state
== DScommandSentLow
);
247 ASSERT(m_activeCmd
!= 0);
248 ASSERT(!m_activeCmd
->m_committed
);
250 // commit the command
251 m_activeCmd
->m_committed
= true;
253 // now the debugger is officially working on the command
254 m_state
= m_state
== DScommandSent
? DSrunning
: DSrunningLow
;
256 // set the flag that reflects whether the program is really running
257 switch (m_activeCmd
->m_cmd
) {
258 case DCrun
: case DCcont
: case DCnext
: case DCstep
: case DCfinish
: case DCuntil
:
259 emit
inferiorRunning();
265 // re-receive delayed output
266 while (!m_delayedOutput
.empty()) {
267 QByteArray delayed
= m_delayedOutput
.front();
268 m_delayedOutput
.pop();
269 slotReceiveOutput(0, const_cast<char*>(delayed
.data()), delayed
.size());
273 void DebuggerDriver::slotReceiveOutput(K3Process
*, char* buffer
, int buflen
)
276 * The debugger should be running (processing a command) at this point.
277 * If it is not, it is still idle because we haven't received the
278 * wroteStdin signal yet, in which case there must be an active command
279 * which is not commited.
281 if (m_state
== DScommandSent
|| m_state
== DScommandSentLow
) {
282 ASSERT(m_activeCmd
!= 0);
283 ASSERT(!m_activeCmd
->m_committed
);
285 * We received output before we got signal wroteStdin. Collect this
286 * output, it will be re-sent by commandRead when it gets the
287 * acknowledgment for the uncommitted command.
289 m_delayedOutput
.push(QByteArray().duplicate(buffer
, buflen
));
292 // write to log file (do not log delayed output - it would appear twice)
293 if (m_logFile
.isOpen()) {
294 m_logFile
.writeBlock(buffer
, buflen
);
299 * gdb sometimes produces stray output while it's idle. This happens if
300 * it receives a signal, most prominently a SIGCONT after a SIGTSTP:
301 * The user haltet kdbg with Ctrl-Z, then continues it with "fg", which
302 * also continues gdb, which repeats the prompt!
304 if (m_activeCmd
== 0 && m_state
!= DSinterrupted
) {
306 TRACE("ignoring stray output: " + QString::fromLatin1(buffer
, buflen
));
309 ASSERT(m_state
== DSrunning
|| m_state
== DSrunningLow
|| m_state
== DSinterrupted
);
310 ASSERT(m_activeCmd
!= 0 || m_state
== DSinterrupted
);
312 // collect output until next prompt string is found
315 if (m_outputLen
+ buflen
>= m_outputAlloc
) {
317 * Must enlarge m_output: double it. Note: That particular
318 * sequence of commandes here ensures exception safety.
320 int newSize
= m_outputAlloc
* 2;
321 char* newBuf
= new char[newSize
];
322 memcpy(newBuf
, m_output
, m_outputLen
);
325 m_outputAlloc
= newSize
;
327 memcpy(m_output
+m_outputLen
, buffer
, buflen
);
328 m_outputLen
+= buflen
;
329 m_output
[m_outputLen
] = '\0';
331 // check for a prompt
332 int promptStart
= findPrompt(m_output
, m_outputLen
);
333 if (promptStart
>= 0)
337 // terminate output before the prompt
338 m_output
[promptStart
] = '\0';
341 * We've got output for the active command. But if it was
342 * interrupted, ignore it.
344 if (m_state
!= DSinterrupted
) {
346 * m_state shouldn't be DSidle while we are parsing the output
347 * so that all commands produced by parse() go into the queue
348 * instead of being written to gdb immediately.
350 ASSERT(m_state
!= DSidle
);
351 CmdQueueItem
* cmd
= m_activeCmd
;
353 commandFinished(cmd
);
360 // also clear delayed output if interrupted
361 if (m_state
== DSinterrupted
) {
362 m_delayedOutput
= std::queue
<QByteArray
>();
366 * We parsed some output successfully. Unless there's more delayed
367 * output, the debugger must be idle now, so send down the next
370 if (m_delayedOutput
.empty()) {
371 if (m_hipriCmdQueue
.empty() && m_lopriCmdQueue
.empty()) {
372 // no pending commands
374 emit
enterIdleState();
382 void DebuggerDriver::dequeueCmdByVar(VarTree
* var
)
387 std::list
<CmdQueueItem
*>::iterator i
= m_lopriCmdQueue
.begin();
388 while (i
!= m_lopriCmdQueue
.end()) {
389 if ((*i
)->m_expr
!= 0 && var
->isAncestorEq((*i
)->m_expr
)) {
390 // this is indeed a critical command; delete it
391 TRACE("removing critical lopri-cmd: " + (*i
)->m_cmdString
);
393 m_lopriCmdQueue
.erase(i
++);
400 QString
DebuggerDriver::editableValue(VarTree
* value
)
402 // by default, let the user edit what is visible
403 return value
->value();
407 StackFrame::~StackFrame()
413 DbgAddr::DbgAddr(const QString
& aa
) :
420 * We strip off the leading 0x and any leading zeros.
422 void DbgAddr::cleanAddr()
427 while (a
[0] == '0' || a
[0] == 'x') {
432 void DbgAddr::operator=(const QString
& aa
)
439 /* Re-attach 0x in front of the address */
440 QString
DbgAddr::asString() const
448 bool operator==(const DbgAddr
& a1
, const DbgAddr
& a2
)
450 return QString::compare(a1
.a
, a2
.a
) == 0;
453 bool operator>(const DbgAddr
& a1
, const DbgAddr
& a2
)
455 if (a1
.a
.length() > a2
.a
.length())
457 if (a1
.a
.length() < a2
.a
.length())
459 return QString::compare(a1
.a
, a2
.a
) > 0;
463 Breakpoint::Breakpoint() :
473 #include "dbgdriver.moc"