OSDN Git Service

905c2b809781ceae51204d8e1d1dcf4b06a89186
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / lldb / ipcenginehost.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "ipcenginehost.h"
35
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"
51
52 #include <utils/qtcassert.h>
53
54 #include <QtCore/QSysInfo>
55 #include <QtCore/QDebug>
56 #include <QtCore/QFileInfo>
57 #include <QtCore/QTimer>
58 #include <QtNetwork/QLocalSocket>
59
60 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
61 #define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::LittleEndian)
62 #else
63 #define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::BigEndian)
64 #endif
65
66 namespace Debugger {
67 namespace Internal {
68
69 IPCEngineHost::IPCEngineHost (const DebuggerStartParameters &startParameters)
70     : DebuggerEngine(startParameters)
71     , m_localGuest(0)
72     , m_nextMessagePayloadSize(0)
73     , m_cookie(1)
74     , m_device(0)
75 {
76     connect(this, SIGNAL(stateChanged(Debugger::DebuggerState)), SLOT(m_stateChanged(Debugger::DebuggerState)));
77 }
78
79 IPCEngineHost::~IPCEngineHost()
80 {
81     delete m_device;
82 }
83
84 void IPCEngineHost::setLocalGuest(IPCEngineGuest *guest)
85 {
86     m_localGuest = guest;
87 }
88
89 void IPCEngineHost::setGuestDevice(QIODevice *device)
90 {
91     if (m_device) {
92         disconnect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead()));
93         delete m_device;
94     }
95     m_device = device;
96     if (m_device)
97         connect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead()));
98 }
99
100 void IPCEngineHost::setupEngine()
101 {
102     QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
103     rpcCall(SetupEngine);
104 }
105
106 void IPCEngineHost::setupInferior()
107 {
108     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
109     QByteArray p;
110     {
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();
116     }
117     rpcCall(SetupInferior, p);
118 }
119
120 void IPCEngineHost::runEngine()
121 {
122     QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
123     rpcCall(RunEngine);
124 }
125
126 void IPCEngineHost::shutdownInferior()
127 {
128     QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
129     rpcCall(ShutdownInferior);
130 }
131
132 void IPCEngineHost::shutdownEngine()
133 {
134     rpcCall(ShutdownEngine);
135 }
136
137 void IPCEngineHost::detachDebugger()
138 {
139     rpcCall(DetachDebugger);
140 }
141
142 void IPCEngineHost::executeStep()
143 {
144     rpcCall(ExecuteStep);
145 }
146
147 void IPCEngineHost::executeStepOut()
148 {
149     rpcCall(ExecuteStepOut);
150 }
151
152 void IPCEngineHost::executeNext()
153 {
154     rpcCall(ExecuteNext);
155 }
156
157 void IPCEngineHost::executeStepI()
158 {
159     rpcCall(ExecuteStepI);
160 }
161
162 void IPCEngineHost::executeNextI()
163 {
164     rpcCall(ExecuteNextI);
165 }
166
167 void IPCEngineHost::continueInferior()
168 {
169     QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
170     resetLocation();
171     rpcCall(ContinueInferior);
172 }
173
174 void IPCEngineHost::interruptInferior()
175 {
176     QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
177     rpcCall(InterruptInferior);
178 }
179
180 void IPCEngineHost::executeRunToLine(const ContextData &data)
181 {
182     QByteArray p;
183     {
184         QDataStream s(&p, QIODevice::WriteOnly);
185         SET_NATIVE_BYTE_ORDER(s);
186         s << data.fileName;
187         s << quint64(data.lineNumber);
188     }
189     rpcCall(ExecuteRunToLine, p);
190 }
191
192 void IPCEngineHost::executeRunToFunction(const QString &functionName)
193 {
194     QByteArray p;
195     {
196         QDataStream s(&p, QIODevice::WriteOnly);
197         SET_NATIVE_BYTE_ORDER(s);
198         s << functionName;
199     }
200     rpcCall(ExecuteRunToFunction, p);
201 }
202
203 void IPCEngineHost::executeJumpToLine(const ContextData &data)
204 {
205     QByteArray p;
206     {
207         QDataStream s(&p, QIODevice::WriteOnly);
208         SET_NATIVE_BYTE_ORDER(s);
209         s << data.fileName;
210         s << quint64(data.lineNumber);
211     }
212     rpcCall(ExecuteJumpToLine, p);
213 }
214
215
216 void IPCEngineHost::activateFrame(int index)
217 {
218     resetLocation();
219     QByteArray p;
220     {
221         QDataStream s(&p, QIODevice::WriteOnly);
222         SET_NATIVE_BYTE_ORDER(s);
223         s << quint64(index);
224     }
225     rpcCall(ActivateFrame, p);
226 }
227
228 void IPCEngineHost::selectThread(int index)
229 {
230     resetLocation();
231     Threads threads = threadsHandler()->threads();
232     QTC_ASSERT(index < threads.size(), return);
233     QByteArray p;
234     {
235         QDataStream s(&p, QIODevice::WriteOnly);
236         SET_NATIVE_BYTE_ORDER(s);
237         s << quint64(threads.at(index).id);
238     }
239     rpcCall(SelectThread, p);
240 }
241
242 void IPCEngineHost::fetchDisassembler(DisassemblerAgent *v)
243 {
244     quint64 address = v->location().address();
245     m_frameToDisassemblerAgent.insert(address, v);
246     QByteArray p;
247     {
248         QDataStream s(&p, QIODevice::WriteOnly);
249         SET_NATIVE_BYTE_ORDER(s);
250         s << address;
251     }
252     rpcCall(Disassemble, p);
253 }
254
255 void IPCEngineHost::insertBreakpoint(BreakpointId id)
256 {
257     breakHandler()->notifyBreakpointInsertProceeding(id);
258     QByteArray p;
259     {
260         QDataStream s(&p, QIODevice::WriteOnly);
261         SET_NATIVE_BYTE_ORDER(s);
262         s << id;
263         s << breakHandler()->breakpointData(id);
264     }
265     rpcCall(AddBreakpoint, p);
266 }
267
268 void IPCEngineHost::removeBreakpoint(BreakpointId id)
269 {
270     breakHandler()->notifyBreakpointRemoveProceeding(id);
271     QByteArray p;
272     {
273         QDataStream s(&p, QIODevice::WriteOnly);
274         SET_NATIVE_BYTE_ORDER(s);
275         s << id;
276     }
277     rpcCall(RemoveBreakpoint, p);
278 }
279
280 void IPCEngineHost::changeBreakpoint(BreakpointId id)
281 {
282     breakHandler()->notifyBreakpointChangeProceeding(id);
283     QByteArray p;
284     {
285         QDataStream s(&p, QIODevice::WriteOnly);
286         SET_NATIVE_BYTE_ORDER(s);
287         s << id;
288         s << breakHandler()->breakpointData(id);
289     }
290     rpcCall(RemoveBreakpoint, p);
291 }
292
293 void IPCEngineHost::updateWatchData(const WatchData &data,
294             const WatchUpdateFlags &flags)
295 {
296     Q_UNUSED(flags);
297     QByteArray p;
298     {
299         QDataStream s(&p, QIODevice::WriteOnly);
300         SET_NATIVE_BYTE_ORDER(s);
301         s << data;
302     }
303     rpcCall(RequestUpdateWatchData, p);
304 }
305
306 void IPCEngineHost::fetchFrameSource(qint64 id)
307 {
308     QByteArray p;
309     {
310         QDataStream s(&p, QIODevice::WriteOnly);
311         SET_NATIVE_BYTE_ORDER(s);
312         s << id;
313     }
314     rpcCall(FetchFrameSource, p);
315 }
316
317 void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
318 {
319     switch (f) {
320         default: {
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);
325     }
326             nuke();
327             break;
328         case IPCEngineGuest::NotifyEngineSetupOk:
329             notifyEngineSetupOk();
330             break;
331         case IPCEngineGuest::NotifyEngineSetupFailed:
332             notifyEngineSetupFailed();
333             break;
334         case IPCEngineGuest::NotifyEngineRunFailed:
335             notifyEngineRunFailed();
336             break;
337         case IPCEngineGuest::NotifyInferiorSetupOk:
338             attemptBreakpointSynchronization();
339             notifyInferiorSetupOk();
340             break;
341         case IPCEngineGuest::NotifyInferiorSetupFailed:
342             notifyInferiorSetupFailed();
343             break;
344         case IPCEngineGuest::NotifyEngineRunAndInferiorRunOk:
345             notifyEngineRunAndInferiorRunOk();
346             break;
347         case IPCEngineGuest::NotifyEngineRunAndInferiorStopOk:
348             notifyEngineRunAndInferiorStopOk();
349             break;
350         case IPCEngineGuest::NotifyInferiorRunRequested:
351             notifyInferiorRunRequested();
352             break;
353         case IPCEngineGuest::NotifyInferiorRunOk:
354             notifyInferiorRunOk();
355             break;
356         case IPCEngineGuest::NotifyInferiorRunFailed:
357             notifyInferiorRunFailed();
358             break;
359         case IPCEngineGuest::NotifyInferiorStopOk:
360             notifyInferiorStopOk();
361             break;
362         case IPCEngineGuest::NotifyInferiorSpontaneousStop:
363             notifyInferiorSpontaneousStop();
364             break;
365         case IPCEngineGuest::NotifyInferiorStopFailed:
366             notifyInferiorStopFailed();
367             break;
368         case IPCEngineGuest::NotifyInferiorExited:
369             notifyInferiorExited();
370             break;
371         case IPCEngineGuest::NotifyInferiorShutdownOk:
372             notifyInferiorShutdownOk();
373             break;
374         case IPCEngineGuest::NotifyInferiorShutdownFailed:
375             notifyInferiorShutdownFailed();
376             break;
377         case IPCEngineGuest::NotifyEngineSpontaneousShutdown:
378             notifyEngineSpontaneousShutdown();
379             break;
380         case IPCEngineGuest::NotifyEngineShutdownOk:
381             notifyEngineShutdownOk();
382             break;
383         case IPCEngineGuest::NotifyEngineShutdownFailed:
384             notifyEngineShutdownFailed();
385             break;
386         case IPCEngineGuest::NotifyInferiorIll:
387             notifyInferiorIll();
388             break;
389         case IPCEngineGuest::NotifyEngineIll:
390             notifyEngineIll();
391             break;
392         case IPCEngineGuest::NotifyInferiorPid:
393             {
394                 QDataStream s(payload);
395                 SET_NATIVE_BYTE_ORDER(s);
396                 quint64 pid;
397                 s >> pid;
398                 notifyInferiorPid(pid);
399             }
400             break;
401         case IPCEngineGuest::ShowStatusMessage:
402             {
403                 QDataStream s(payload);
404                 SET_NATIVE_BYTE_ORDER(s);
405                 QString msg;
406                 qint64 timeout;
407                 s >> msg;
408                 s >> timeout;
409                 showStatusMessage(msg, timeout);
410             }
411             break;
412         case IPCEngineGuest::ShowMessage:
413             {
414                 QDataStream s(payload);
415                 SET_NATIVE_BYTE_ORDER(s);
416                 QString msg;
417                 qint16 channel;
418                 qint64 timeout;
419                 s >> msg;
420                 s >> channel;
421                 s >> timeout;
422                 showMessage(msg, channel, timeout);
423             }
424             break;
425         case IPCEngineGuest::CurrentFrameChanged:
426             {
427                 QDataStream s(payload);
428                 SET_NATIVE_BYTE_ORDER(s);
429                 quint64 token;
430                 s >> token;
431
432                 resetLocation();
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();
441             }
442             break;
443         case IPCEngineGuest::CurrentThreadChanged:
444             {
445                 QDataStream s(payload);
446                 SET_NATIVE_BYTE_ORDER(s);
447                 quint64 token;
448                 s >> token;
449                 threadsHandler()->setCurrentThreadId(token);
450             }
451             break;
452         case IPCEngineGuest::ListFrames:
453             {
454                 QDataStream s(payload);
455                 SET_NATIVE_BYTE_ORDER(s);
456                 StackFrames frames;
457                 s >> frames;
458                 stackHandler()->setFrames(frames);
459             }
460             break;
461         case IPCEngineGuest::ListThreads:
462             {
463                 QDataStream s(payload);
464                 SET_NATIVE_BYTE_ORDER(s);
465                 Threads threads;
466                 s >> threads;
467                 threadsHandler()->setThreads(threads);
468             }
469             break;
470         case IPCEngineGuest::Disassembled:
471             {
472                 QDataStream s(payload);
473                 SET_NATIVE_BYTE_ORDER(s);
474                 quint64 pc;
475                 DisassemblerLines lines;
476                 s >> pc;
477                 s >> lines;
478                 DisassemblerAgent *view = m_frameToDisassemblerAgent.take(pc);
479                 if (view)
480                     view->setContents(lines);
481             }
482             break;
483         case IPCEngineGuest::UpdateWatchData:
484             {
485                 QDataStream s(payload);
486                 SET_NATIVE_BYTE_ORDER(s);
487                 bool fullCycle;
488                 qint64 count;
489                 QList<WatchData> wd;
490                 s >> fullCycle;
491                 s >> count;
492                 for (qint64 i = 0; i < count; ++i) {
493                     WatchData d;
494                     s >> d;
495                     wd.append(d);
496                 }
497                 WatchHandler *wh = watchHandler();
498                 if (!wh)
499                     break;
500                 wh->beginCycle(fullCycle);
501                 wh->insertBulkData(wd);
502                 wh->endCycle(fullCycle);
503             }
504             break;
505         case IPCEngineGuest::NotifyAddBreakpointOk:
506             {
507                 attemptBreakpointSynchronization();
508                 QDataStream s(payload);
509                 SET_NATIVE_BYTE_ORDER(s);
510                 BreakpointId id;
511                 s >> id;
512                 breakHandler()->notifyBreakpointInsertOk(id);
513             }
514             break;
515         case IPCEngineGuest::NotifyAddBreakpointFailed:
516             {
517                 QDataStream s(payload);
518                 SET_NATIVE_BYTE_ORDER(s);
519                 BreakpointId id;
520                 s >> id;
521                 breakHandler()->notifyBreakpointInsertFailed(id);
522             }
523             break;
524         case IPCEngineGuest::NotifyRemoveBreakpointOk:
525             {
526                 QDataStream s(payload);
527                 SET_NATIVE_BYTE_ORDER(s);
528                 BreakpointId id;
529                 s >> id;
530                 breakHandler()->notifyBreakpointRemoveOk(id);
531             }
532             break;
533         case IPCEngineGuest::NotifyRemoveBreakpointFailed:
534             {
535                 QDataStream s(payload);
536                 SET_NATIVE_BYTE_ORDER(s);
537                 BreakpointId id;
538                 s >> id;
539                 breakHandler()->notifyBreakpointRemoveFailed(id);
540             }
541             break;
542         case IPCEngineGuest::NotifyChangeBreakpointOk:
543             {
544                 QDataStream s(payload);
545                 SET_NATIVE_BYTE_ORDER(s);
546                 BreakpointId id;
547                 s >> id;
548                 breakHandler()->notifyBreakpointChangeOk(id);
549             }
550             break;
551         case IPCEngineGuest::NotifyChangeBreakpointFailed:
552             {
553                 QDataStream s(payload);
554                 SET_NATIVE_BYTE_ORDER(s);
555                 BreakpointId id;
556                 s >> id;
557                 breakHandler()->notifyBreakpointChangeFailed(id);
558             }
559             break;
560         case IPCEngineGuest::NotifyBreakpointAdjusted:
561             {
562                 QDataStream s(payload);
563                 SET_NATIVE_BYTE_ORDER(s);
564                 BreakpointId id;
565                 BreakpointParameters d;
566                 s >> id >> d;
567                 breakHandler()->notifyBreakpointAdjusted(id, d);
568             }
569             break;
570         case IPCEngineGuest::FrameSourceFetched:
571             {
572                 QDataStream s(payload);
573                 SET_NATIVE_BYTE_ORDER(s);
574                 qint64 token;
575                 QString path;
576                 QString source;
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();
583             }
584             break;
585     }
586 }
587
588 void IPCEngineHost::m_stateChanged(const Debugger::DebuggerState &state)
589 {
590     QByteArray p;
591     {
592         QDataStream s(&p, QIODevice::WriteOnly);
593         SET_NATIVE_BYTE_ORDER(s);
594         s << (qint64)state;
595     }
596     rpcCall(StateChanged, p);
597
598 }
599
600 void IPCEngineHost::rpcCall(Function f, QByteArray payload)
601 {
602     if (m_localGuest) {
603         QMetaObject::invokeMethod(m_localGuest,
604                 "rpcCallback",
605                 Qt::QueuedConnection,
606                 Q_ARG(quint64, f),
607                 Q_ARG(QByteArray, payload));
608     } else if (m_device) {
609         QByteArray header;
610         {
611             QDataStream s(&header, QIODevice::WriteOnly);
612             SET_NATIVE_BYTE_ORDER(s);
613             s << m_cookie++;
614             s << (quint64) f;
615             s << (quint64) payload.size();
616         }
617         m_device->write(header);
618         m_device->write(payload);
619         m_device->putChar('T');
620         QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_device);
621         if (sock)
622             sock->flush();
623     }
624 }
625
626 void IPCEngineHost::readyRead()
627 {
628     QDataStream s(m_device);
629     SET_NATIVE_BYTE_ORDER(s);
630     if (!m_nextMessagePayloadSize) {
631         if (quint64(m_device->bytesAvailable ()) < 3 * sizeof(quint64))
632             return;
633         s >> m_nextMessageCookie;
634         s >> m_nextMessageFunction;
635         s >> m_nextMessagePayloadSize;
636         m_nextMessagePayloadSize += 1; // Terminator and "got header" marker.
637     }
638
639     quint64 ba = m_device->bytesAvailable();
640     if (ba < m_nextMessagePayloadSize)
641         return;
642
643     QByteArray payload = m_device->read(m_nextMessagePayloadSize - 1);
644
645     char terminator;
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"));
650         nuke();
651         return;
652     }
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()));
657 }
658
659 } // namespace Internal
660 } // namespace Debugger
661
662