1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "ipcenginehost.h"
36 #include "ipcengineguest.h"
37 #include "debuggerstartparameters.h"
38 #include "breakhandler.h"
39 #include "breakpoint.h"
40 #include "disassemblerlines.h"
41 #include "moduleshandler.h"
42 #include "registerhandler.h"
43 #include "stackhandler.h"
44 #include "watchhandler.h"
45 #include "watchutils.h"
46 #include "threadshandler.h"
47 #include "disassembleragent.h"
48 #include "memoryagent.h"
49 #include "debuggerstreamops.h"
50 #include "debuggercore.h"
52 #include <utils/qtcassert.h>
54 #include <QtCore/QSysInfo>
55 #include <QtCore/QDebug>
56 #include <QtCore/QFileInfo>
57 #include <QtCore/QTimer>
58 #include <QtNetwork/QLocalSocket>
60 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
61 #define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::LittleEndian)
63 #define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::BigEndian)
69 IPCEngineHost::IPCEngineHost (const DebuggerStartParameters &startParameters)
70 : DebuggerEngine(startParameters)
72 , m_nextMessagePayloadSize(0)
76 connect(this, SIGNAL(stateChanged(Debugger::DebuggerState)), SLOT(m_stateChanged(Debugger::DebuggerState)));
79 IPCEngineHost::~IPCEngineHost()
84 void IPCEngineHost::setLocalGuest(IPCEngineGuest *guest)
89 void IPCEngineHost::setGuestDevice(QIODevice *device)
92 disconnect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead()));
97 connect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead()));
100 void IPCEngineHost::setupEngine()
102 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
103 rpcCall(SetupEngine);
106 void IPCEngineHost::setupInferior()
108 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
111 QDataStream s(&p, QIODevice::WriteOnly);
112 SET_NATIVE_BYTE_ORDER(s);
113 s << QFileInfo(startParameters().executable).absoluteFilePath();
114 s << startParameters().processArgs;
115 s << startParameters().environment.toStringList();
117 rpcCall(SetupInferior, p);
120 void IPCEngineHost::runEngine()
122 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
126 void IPCEngineHost::shutdownInferior()
128 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
129 rpcCall(ShutdownInferior);
132 void IPCEngineHost::shutdownEngine()
134 rpcCall(ShutdownEngine);
137 void IPCEngineHost::detachDebugger()
139 rpcCall(DetachDebugger);
142 void IPCEngineHost::executeStep()
144 rpcCall(ExecuteStep);
147 void IPCEngineHost::executeStepOut()
149 rpcCall(ExecuteStepOut);
152 void IPCEngineHost::executeNext()
154 rpcCall(ExecuteNext);
157 void IPCEngineHost::executeStepI()
159 rpcCall(ExecuteStepI);
162 void IPCEngineHost::executeNextI()
164 rpcCall(ExecuteNextI);
167 void IPCEngineHost::continueInferior()
169 QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
171 rpcCall(ContinueInferior);
174 void IPCEngineHost::interruptInferior()
176 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
177 rpcCall(InterruptInferior);
180 void IPCEngineHost::executeRunToLine(const ContextData &data)
184 QDataStream s(&p, QIODevice::WriteOnly);
185 SET_NATIVE_BYTE_ORDER(s);
187 s << quint64(data.lineNumber);
189 rpcCall(ExecuteRunToLine, p);
192 void IPCEngineHost::executeRunToFunction(const QString &functionName)
196 QDataStream s(&p, QIODevice::WriteOnly);
197 SET_NATIVE_BYTE_ORDER(s);
200 rpcCall(ExecuteRunToFunction, p);
203 void IPCEngineHost::executeJumpToLine(const ContextData &data)
207 QDataStream s(&p, QIODevice::WriteOnly);
208 SET_NATIVE_BYTE_ORDER(s);
210 s << quint64(data.lineNumber);
212 rpcCall(ExecuteJumpToLine, p);
216 void IPCEngineHost::activateFrame(int index)
221 QDataStream s(&p, QIODevice::WriteOnly);
222 SET_NATIVE_BYTE_ORDER(s);
225 rpcCall(ActivateFrame, p);
228 void IPCEngineHost::selectThread(int index)
231 Threads threads = threadsHandler()->threads();
232 QTC_ASSERT(index < threads.size(), return);
235 QDataStream s(&p, QIODevice::WriteOnly);
236 SET_NATIVE_BYTE_ORDER(s);
237 s << quint64(threads.at(index).id);
239 rpcCall(SelectThread, p);
242 void IPCEngineHost::fetchDisassembler(DisassemblerAgent *v)
244 quint64 address = v->location().address();
245 m_frameToDisassemblerAgent.insert(address, v);
248 QDataStream s(&p, QIODevice::WriteOnly);
249 SET_NATIVE_BYTE_ORDER(s);
252 rpcCall(Disassemble, p);
255 void IPCEngineHost::insertBreakpoint(BreakpointId id)
257 breakHandler()->notifyBreakpointInsertProceeding(id);
260 QDataStream s(&p, QIODevice::WriteOnly);
261 SET_NATIVE_BYTE_ORDER(s);
263 s << breakHandler()->breakpointData(id);
265 rpcCall(AddBreakpoint, p);
268 void IPCEngineHost::removeBreakpoint(BreakpointId id)
270 breakHandler()->notifyBreakpointRemoveProceeding(id);
273 QDataStream s(&p, QIODevice::WriteOnly);
274 SET_NATIVE_BYTE_ORDER(s);
277 rpcCall(RemoveBreakpoint, p);
280 void IPCEngineHost::changeBreakpoint(BreakpointId id)
282 breakHandler()->notifyBreakpointChangeProceeding(id);
285 QDataStream s(&p, QIODevice::WriteOnly);
286 SET_NATIVE_BYTE_ORDER(s);
288 s << breakHandler()->breakpointData(id);
290 rpcCall(RemoveBreakpoint, p);
293 void IPCEngineHost::updateWatchData(const WatchData &data,
294 const WatchUpdateFlags &flags)
299 QDataStream s(&p, QIODevice::WriteOnly);
300 SET_NATIVE_BYTE_ORDER(s);
303 rpcCall(RequestUpdateWatchData, p);
306 void IPCEngineHost::fetchFrameSource(qint64 id)
310 QDataStream s(&p, QIODevice::WriteOnly);
311 SET_NATIVE_BYTE_ORDER(s);
314 rpcCall(FetchFrameSource, p);
317 void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
321 showMessage(QLatin1String("IPC Error: unhandled id in guest to host call"));
322 const QString logMessage = tr("Fatal engine shutdown. Incompatible binary or IPC error.");
323 showMessage(logMessage, LogError);
324 showStatusMessage(logMessage);
328 case IPCEngineGuest::NotifyEngineSetupOk:
329 notifyEngineSetupOk();
331 case IPCEngineGuest::NotifyEngineSetupFailed:
332 notifyEngineSetupFailed();
334 case IPCEngineGuest::NotifyEngineRunFailed:
335 notifyEngineRunFailed();
337 case IPCEngineGuest::NotifyInferiorSetupOk:
338 attemptBreakpointSynchronization();
339 notifyInferiorSetupOk();
341 case IPCEngineGuest::NotifyInferiorSetupFailed:
342 notifyInferiorSetupFailed();
344 case IPCEngineGuest::NotifyEngineRunAndInferiorRunOk:
345 notifyEngineRunAndInferiorRunOk();
347 case IPCEngineGuest::NotifyEngineRunAndInferiorStopOk:
348 notifyEngineRunAndInferiorStopOk();
350 case IPCEngineGuest::NotifyInferiorRunRequested:
351 notifyInferiorRunRequested();
353 case IPCEngineGuest::NotifyInferiorRunOk:
354 notifyInferiorRunOk();
356 case IPCEngineGuest::NotifyInferiorRunFailed:
357 notifyInferiorRunFailed();
359 case IPCEngineGuest::NotifyInferiorStopOk:
360 notifyInferiorStopOk();
362 case IPCEngineGuest::NotifyInferiorSpontaneousStop:
363 notifyInferiorSpontaneousStop();
365 case IPCEngineGuest::NotifyInferiorStopFailed:
366 notifyInferiorStopFailed();
368 case IPCEngineGuest::NotifyInferiorExited:
369 notifyInferiorExited();
371 case IPCEngineGuest::NotifyInferiorShutdownOk:
372 notifyInferiorShutdownOk();
374 case IPCEngineGuest::NotifyInferiorShutdownFailed:
375 notifyInferiorShutdownFailed();
377 case IPCEngineGuest::NotifyEngineSpontaneousShutdown:
378 notifyEngineSpontaneousShutdown();
380 case IPCEngineGuest::NotifyEngineShutdownOk:
381 notifyEngineShutdownOk();
383 case IPCEngineGuest::NotifyEngineShutdownFailed:
384 notifyEngineShutdownFailed();
386 case IPCEngineGuest::NotifyInferiorIll:
389 case IPCEngineGuest::NotifyEngineIll:
392 case IPCEngineGuest::NotifyInferiorPid:
394 QDataStream s(payload);
395 SET_NATIVE_BYTE_ORDER(s);
398 notifyInferiorPid(pid);
401 case IPCEngineGuest::ShowStatusMessage:
403 QDataStream s(payload);
404 SET_NATIVE_BYTE_ORDER(s);
409 showStatusMessage(msg, timeout);
412 case IPCEngineGuest::ShowMessage:
414 QDataStream s(payload);
415 SET_NATIVE_BYTE_ORDER(s);
422 showMessage(msg, channel, timeout);
425 case IPCEngineGuest::CurrentFrameChanged:
427 QDataStream s(payload);
428 SET_NATIVE_BYTE_ORDER(s);
433 StackHandler *sh = stackHandler();
434 sh->setCurrentIndex(token);
435 if (!sh->currentFrame().isUsable() || QFileInfo(sh->currentFrame().file).exists())
436 gotoLocation(Location(sh->currentFrame(), true));
437 else if (!m_sourceAgents.contains(sh->currentFrame().file))
438 fetchFrameSource(token);
439 foreach(SourceAgent *agent, m_sourceAgents.values())
440 agent->updateLocationMarker();
443 case IPCEngineGuest::CurrentThreadChanged:
445 QDataStream s(payload);
446 SET_NATIVE_BYTE_ORDER(s);
449 threadsHandler()->setCurrentThreadId(token);
452 case IPCEngineGuest::ListFrames:
454 QDataStream s(payload);
455 SET_NATIVE_BYTE_ORDER(s);
458 stackHandler()->setFrames(frames);
461 case IPCEngineGuest::ListThreads:
463 QDataStream s(payload);
464 SET_NATIVE_BYTE_ORDER(s);
467 threadsHandler()->setThreads(threads);
470 case IPCEngineGuest::Disassembled:
472 QDataStream s(payload);
473 SET_NATIVE_BYTE_ORDER(s);
475 DisassemblerLines lines;
478 DisassemblerAgent *view = m_frameToDisassemblerAgent.take(pc);
480 view->setContents(lines);
483 case IPCEngineGuest::UpdateWatchData:
485 QDataStream s(payload);
486 SET_NATIVE_BYTE_ORDER(s);
492 for (qint64 i = 0; i < count; ++i) {
497 WatchHandler *wh = watchHandler();
500 wh->beginCycle(fullCycle);
501 wh->insertBulkData(wd);
502 wh->endCycle(fullCycle);
505 case IPCEngineGuest::NotifyAddBreakpointOk:
507 attemptBreakpointSynchronization();
508 QDataStream s(payload);
509 SET_NATIVE_BYTE_ORDER(s);
512 breakHandler()->notifyBreakpointInsertOk(id);
515 case IPCEngineGuest::NotifyAddBreakpointFailed:
517 QDataStream s(payload);
518 SET_NATIVE_BYTE_ORDER(s);
521 breakHandler()->notifyBreakpointInsertFailed(id);
524 case IPCEngineGuest::NotifyRemoveBreakpointOk:
526 QDataStream s(payload);
527 SET_NATIVE_BYTE_ORDER(s);
530 breakHandler()->notifyBreakpointRemoveOk(id);
533 case IPCEngineGuest::NotifyRemoveBreakpointFailed:
535 QDataStream s(payload);
536 SET_NATIVE_BYTE_ORDER(s);
539 breakHandler()->notifyBreakpointRemoveFailed(id);
542 case IPCEngineGuest::NotifyChangeBreakpointOk:
544 QDataStream s(payload);
545 SET_NATIVE_BYTE_ORDER(s);
548 breakHandler()->notifyBreakpointChangeOk(id);
551 case IPCEngineGuest::NotifyChangeBreakpointFailed:
553 QDataStream s(payload);
554 SET_NATIVE_BYTE_ORDER(s);
557 breakHandler()->notifyBreakpointChangeFailed(id);
560 case IPCEngineGuest::NotifyBreakpointAdjusted:
562 QDataStream s(payload);
563 SET_NATIVE_BYTE_ORDER(s);
565 BreakpointParameters d;
567 breakHandler()->notifyBreakpointAdjusted(id, d);
570 case IPCEngineGuest::FrameSourceFetched:
572 QDataStream s(payload);
573 SET_NATIVE_BYTE_ORDER(s);
577 s >> token >> path >> source;
578 SourceAgent *agent = new SourceAgent(this);
579 agent->setSourceProducerName(startParameters().connParams.host);
580 agent->setContent(path, source);
581 m_sourceAgents.insert(path, agent);
582 agent->updateLocationMarker();
588 void IPCEngineHost::m_stateChanged(const Debugger::DebuggerState &state)
592 QDataStream s(&p, QIODevice::WriteOnly);
593 SET_NATIVE_BYTE_ORDER(s);
596 rpcCall(StateChanged, p);
600 void IPCEngineHost::rpcCall(Function f, QByteArray payload)
603 QMetaObject::invokeMethod(m_localGuest,
605 Qt::QueuedConnection,
607 Q_ARG(QByteArray, payload));
608 } else if (m_device) {
611 QDataStream s(&header, QIODevice::WriteOnly);
612 SET_NATIVE_BYTE_ORDER(s);
615 s << (quint64) payload.size();
617 m_device->write(header);
618 m_device->write(payload);
619 m_device->putChar('T');
620 QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_device);
626 void IPCEngineHost::readyRead()
628 QDataStream s(m_device);
629 SET_NATIVE_BYTE_ORDER(s);
630 if (!m_nextMessagePayloadSize) {
631 if (quint64(m_device->bytesAvailable ()) < 3 * sizeof(quint64))
633 s >> m_nextMessageCookie;
634 s >> m_nextMessageFunction;
635 s >> m_nextMessagePayloadSize;
636 m_nextMessagePayloadSize += 1; // Terminator and "got header" marker.
639 quint64 ba = m_device->bytesAvailable();
640 if (ba < m_nextMessagePayloadSize)
643 QByteArray payload = m_device->read(m_nextMessagePayloadSize - 1);
646 m_device->getChar(&terminator);
647 if (terminator != 'T') {
648 showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or IPC error."));
649 showMessage(QLatin1String("IPC Error: terminator missing"));
653 rpcCallback(m_nextMessageFunction, payload);
654 m_nextMessagePayloadSize = 0;
655 if (quint64(m_device->bytesAvailable()) >= 3 * sizeof(quint64))
656 QTimer::singleShot(0, this, SLOT(readyRead()));
659 } // namespace Internal
660 } // namespace Debugger