OSDN Git Service

84644bf1ebd5d5181680ab10db72f3d9bdf46942
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / lldb / guest / lldbengineguest.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 #define QT_NO_CAST_FROM_ASCII
35
36 #include "lldbengineguest.h"
37
38 #include "debuggeractions.h"
39 #include "debuggerconstants.h"
40 #include "debuggerdialogs.h"
41 #include "debuggerplugin.h"
42 #include "debuggerstringutils.h"
43
44 #include "breakhandler.h"
45 #include "breakpoint.h"
46 #include "moduleshandler.h"
47 #include "registerhandler.h"
48 #include "stackhandler.h"
49 #include "watchhandler.h"
50 #include "watchutils.h"
51 #include "threadshandler.h"
52
53 #include <utils/qtcassert.h>
54 #include <QtCore/QDebug>
55 #include <QtCore/QProcess>
56 #include <QtCore/QFileInfo>
57 #include <QtCore/QThread>
58 #include <QtCore/QMutexLocker>
59
60 #include <lldb/API/LLDB.h>
61
62 #define DEBUG_FUNC_ENTER \
63     showMessage(QString(QLatin1String("LLDB guest engine: %1 ")) \
64     .arg(QLatin1String(Q_FUNC_INFO))); \
65     qDebug("%s", Q_FUNC_INFO)
66
67 #define SYNC_INFERIOR_OR(x)  if (m_running) { x; }
68
69
70 namespace Debugger {
71 namespace Internal {
72
73 void LldbEventListener::listen(lldb::SBListener *listener)
74 {
75     while (true) {
76         lldb::SBEvent event;
77         if (listener->WaitForEvent(1000, event))
78             emit lldbEvent(&event);
79     }
80 }
81
82 LldbEngineGuest::LldbEngineGuest()
83     : IPCEngineGuest()
84     , m_running (false)
85     , m_worker  (new LldbEventListener)
86     , m_lldb    (new lldb::SBDebugger)
87     , m_target  (new lldb::SBTarget)
88     , m_process (new lldb::SBProcess)
89     , m_listener(new lldb::SBListener("bla"))
90     , m_relistFrames (false)
91 #if defined(HAVE_LLDB_PRIVATE)
92     , py (new PythonLLDBToGdbMiHack)
93 #endif
94 {
95     qRegisterMetaType<lldb::SBListener *>("lldb::SBListener *");
96     qRegisterMetaType<lldb::SBEvent *>("lldb::SBEvent *");
97
98     m_worker->moveToThread(&m_wThread);
99     connect(m_worker, SIGNAL(lldbEvent(lldb::SBEvent *)), this,
100             SLOT(lldbEvent(lldb::SBEvent *)), Qt::BlockingQueuedConnection);
101     m_wThread.start();
102     setObjectName(QLatin1String("LLDBEngineGuest"));
103 }
104
105 LldbEngineGuest::~LldbEngineGuest()
106 {
107     delete m_lldb;
108     delete m_target;
109     delete m_process;
110     delete m_listener;
111 }
112
113
114 void LldbEngineGuest::nuke()
115 {
116     ::exit(4);
117 }
118
119 void LldbEngineGuest::setupEngine()
120 {
121     DEBUG_FUNC_ENTER;
122
123     lldb::SBDebugger::Initialize();
124
125     *m_lldb = lldb::SBDebugger::Create();
126     m_lldb->Initialize();
127     if (m_lldb->IsValid())
128         notifyEngineSetupOk();
129     else
130         notifyEngineSetupFailed();
131
132 }
133
134 void LldbEngineGuest::setupInferior(const QString &executable,
135         const QStringList &args, const QStringList &env)
136 {
137     DEBUG_FUNC_ENTER;
138
139     foreach (const QString &s, args) {
140         m_arguments.append(s.toLocal8Bit());
141     }
142     foreach (const QString &s, env) {
143         m_environment.append(s.toLocal8Bit());
144     }
145
146     qDebug("creating target for %s", executable.toLocal8Bit().data());
147     showStatusMessage(QLatin1String("starting ") + executable);
148     *m_target = m_lldb->CreateTarget(executable.toLocal8Bit().data());
149     if (!m_target->IsValid()) {
150         notifyInferiorSetupFailed();
151         return;
152     }
153     DEBUG_FUNC_ENTER;
154
155     const char **argp = new const char *[m_arguments.count() + 1];
156     argp[m_arguments.count()] = 0;
157     for (int i = 0; i < m_arguments.count(); i++) {
158         argp[i] = m_arguments[i].data();
159     }
160
161     const char **envp = new const char *[m_environment.count() + 1];
162     envp[m_environment.count()] = 0;
163     for (int i = 0; i < m_environment.count(); i++) {
164         envp[i] = m_environment[i].data();
165     }
166     lldb::SBError err;
167     *m_process = m_target->Launch(argp, envp, NULL, NULL, true, err);
168
169     if (!err.Success()) {
170         showMessage(QString::fromLocal8Bit(err.GetCString()));
171         qDebug() << err.GetCString();
172         notifyInferiorSetupFailed();
173     }
174
175     /*
176      * note, the actual string ptrs are still valid. They are in m_environment.
177      * They probably leak. Considered the marvelous API, there is not much we can do
178      */
179     delete [] envp;
180
181     if (!m_process->IsValid())
182         notifyEngineRunFailed();
183     QTC_ASSERT(m_listener->IsValid(), qDebug() << false);
184     m_listener->StartListeningForEvents(m_process->GetBroadcaster(), UINT32_MAX);
185     QMetaObject::invokeMethod(m_worker, "listen", Qt::QueuedConnection,
186             Q_ARG(lldb::SBListener *, m_listener));
187     notifyInferiorSetupOk();
188 }
189
190 void LldbEngineGuest::runEngine()
191 {
192     DEBUG_FUNC_ENTER;
193     m_process->Continue();
194 }
195
196 void LldbEngineGuest::shutdownInferior()
197 {
198     DEBUG_FUNC_ENTER;
199     m_process->Kill();
200 }
201
202 void LldbEngineGuest::shutdownEngine()
203 {
204     DEBUG_FUNC_ENTER;
205     m_currentFrame = lldb::SBFrame();
206     m_currentThread = lldb::SBThread();
207     m_breakpoints.clear();
208     m_localesCache.clear();
209
210     /*
211      * this leaks. However, Terminate is broken and lldb leaks anyway
212      * We should kill the engine guest process
213      */
214
215     *m_lldb = lldb::SBDebugger();
216     // leakd.Terminate();
217     notifyEngineShutdownOk();
218 }
219
220 void LldbEngineGuest::detachDebugger()
221 {
222     DEBUG_FUNC_ENTER;
223 }
224
225 void LldbEngineGuest::executeStep()
226 {
227     DEBUG_FUNC_ENTER;
228
229     if (!m_currentThread.IsValid())
230         return;
231     m_currentThread.StepInto();
232 }
233
234 void LldbEngineGuest::executeStepOut()
235 {
236     DEBUG_FUNC_ENTER;
237
238     if (!m_currentThread.IsValid())
239         return;
240     m_currentThread.StepOut();
241 }
242
243 void LldbEngineGuest::executeNext()
244 {
245     DEBUG_FUNC_ENTER;
246
247     if (!m_currentThread.IsValid())
248         return;
249     m_currentThread.StepOver();
250 }
251
252 void LldbEngineGuest::executeStepI()
253 {
254     DEBUG_FUNC_ENTER;
255
256     if (!m_currentThread.IsValid())
257         return;
258     m_currentThread.StepInstruction(false);
259 }
260
261 void LldbEngineGuest::executeNextI()
262 {
263     DEBUG_FUNC_ENTER;
264
265     if (!m_currentThread.IsValid())
266         return;
267     m_currentThread.StepInstruction(true);
268 }
269
270 void LldbEngineGuest::continueInferior()
271 {
272     DEBUG_FUNC_ENTER;
273
274     notifyInferiorRunRequested();
275     m_process->Continue();
276     showStatusMessage(QLatin1String("resuming inferior"));
277 }
278 void LldbEngineGuest::interruptInferior()
279 {
280     DEBUG_FUNC_ENTER;
281
282     m_process->Stop();
283     notifyInferiorStopOk();
284     m_relistFrames = true;
285     updateThreads();
286 }
287
288 void LldbEngineGuest::executeRunToLine(const ContextData &data);
289 {
290     DEBUG_FUNC_ENTER;
291
292     // TODO
293     Q_UNUSED(data);
294 }
295
296 void LldbEngineGuest::executeRunToFunction(const QString &functionName)
297 {
298     DEBUG_FUNC_ENTER;
299
300     // TODO
301     Q_UNUSED(functionName);
302 }
303 void LldbEngineGuest::executeJumpToLine(const ContextData &data);
304 {
305     DEBUG_FUNC_ENTER;
306
307     // TODO
308     Q_UNUSED(data);
309 }
310
311 void LldbEngineGuest::activateFrame(qint64 token)
312 {
313     DEBUG_FUNC_ENTER;
314     SYNC_INFERIOR_OR(showMessage(QLatin1String(
315         "activateFrame called while inferior running")); return);
316
317     currentFrameChanged(token);
318     m_localesCache.clear();
319
320     lldb::SBFrame fr = m_currentThread.GetFrameAtIndex(token);
321     m_currentFrame = fr;
322     lldb::SBSymbolContext context = fr.GetSymbolContext(lldb::eSymbolContextEverything);
323     lldb::SBValueList values = fr.GetVariables(true, true, false, true);
324     QList<WatchData> wd;
325     QByteArray iname = "local";
326     for (uint i = 0; i < values.GetSize(); i++) {
327         lldb::SBValue v = values.GetValueAtIndex(i);
328         if (!v.IsInScope(fr))
329             continue;
330         getWatchDataR(v, 1, iname, wd);
331     }
332     updateWatchData(true, wd);
333 }
334
335 void LldbEngineGuest::requestUpdateWatchData(const Internal::WatchData &data,
336         const Internal::WatchUpdateFlags &)
337 {
338     DEBUG_FUNC_ENTER;
339     SYNC_INFERIOR_OR(return);
340
341     lldb::SBValue v = m_localesCache.value(QString::fromUtf8(data.iname));
342     QList<WatchData> wd;
343     for (uint j = 0; j < v.GetNumChildren(); j++) {
344         lldb::SBValue vv = v.GetChildAtIndex(j);
345         getWatchDataR(vv, 1, data.iname, wd);
346     }
347     updateWatchData(false, wd);
348 }
349
350 void LldbEngineGuest::getWatchDataR(lldb::SBValue v, int level,
351         const QByteArray &p_iname, QList<WatchData> &wd)
352 {
353     QByteArray iname = p_iname + '.' + QByteArray(v.GetName());
354     m_localesCache.insert(QString::fromLocal8Bit(iname), v);
355
356 #if defined(HAVE_LLDB_PRIVATE)
357     wd += py->expand(p_iname, v, m_currentFrame, *m_process);
358 #else
359     WatchData d;
360     d.name = QString::fromLocal8Bit(v.GetName());
361     d.iname = iname;
362     d.type = QByteArray(v.GetTypeName()).trimmed();
363     d.value = (QString::fromLocal8Bit(v.GetValue(m_currentFrame)));
364     d.hasChildren = v.GetNumChildren();
365     d.state = WatchData::State(0);
366     wd.append(d);
367 #endif
368
369     if (--level > 0) {
370         for (uint j = 0; j < v.GetNumChildren(); j++) {
371             lldb::SBValue vv = v.GetChildAtIndex(j);
372             getWatchDataR(vv, level, iname, wd);
373         }
374     }
375 }
376
377 void LldbEngineGuest::disassemble(quint64 pc)
378 {
379     DEBUG_FUNC_ENTER;
380     SYNC_INFERIOR_OR(return);
381
382     if (!m_currentThread.IsValid())
383         return;
384     for (uint j = 0; j < m_currentThread.GetNumFrames(); j++) {
385         lldb::SBFrame fr = m_currentThread.GetFrameAtIndex(j);
386         if (pc == fr.GetPCAddress().GetLoadAddress(*m_target)) {
387             QString linesStr = QString::fromLocal8Bit(fr.Disassemble());
388             DisassemblerLines lines;
389             foreach (const QString &lineStr, linesStr.split(QLatin1Char('\n'))) {
390                 lines.appendLine(DisassemblerLine(lineStr));
391             }
392             disassembled(pc, lines);
393         }
394     }
395 }
396 void LldbEngineGuest::fetchFrameSource(qint64 frame)
397 {
398     QFile f(m_frame_to_file.value(frame));
399     f.open(QFile::ReadOnly);
400     frameSourceFetched(frame, QFileInfo(m_frame_to_file.value(frame)).fileName()
401             , QString::fromLocal8Bit(f.readAll()));
402 }
403
404 void LldbEngineGuest::addBreakpoint(BreakpointId id,
405         const Internal::BreakpointParameters &bp_)
406 {
407     DEBUG_FUNC_ENTER;
408     SYNC_INFERIOR_OR(notifyAddBreakpointFailed(id); return);
409
410     Internal::BreakpointParameters bp(bp_);
411
412     lldb::SBBreakpoint llbp = m_target->BreakpointCreateByLocation(
413             bp.fileName.toLocal8Bit().constData(), bp.lineNumber);
414     if (llbp.IsValid()) {
415         m_breakpoints.insert(id, llbp);
416
417         llbp.SetIgnoreCount(bp.ignoreCount);
418         bp.ignoreCount = llbp.GetIgnoreCount();
419         bp.enabled = llbp.IsEnabled();
420
421         lldb::SBBreakpointLocation location = llbp.GetLocationAtIndex(0);
422         if (location.IsValid()) {
423             bp.address = location.GetLoadAddress();
424
425             // FIXME get those from lldb
426             bp.lineNumber = bp.lineNumber;
427             bp.fileName = bp.fileName;
428             notifyAddBreakpointOk(id);
429             showMessage(QLatin1String("[BB] ok."));
430             notifyBreakpointAdjusted(id, bp);
431         } else {
432             m_breakpoints.take(id);
433             showMessage(QLatin1String("[BB] failed. cant resolve yet"));
434 //            notifyAddBreakpointFailed(id);
435 //            notifyAddBreakpointOk(id);
436         }
437     } else {
438         showMessage(QLatin1String("[BB] failed. dunno."));
439         notifyAddBreakpointFailed(id);
440     }
441 }
442
443 void LldbEngineGuest::removeBreakpoint(BreakpointId id)
444 {
445     DEBUG_FUNC_ENTER;
446     SYNC_INFERIOR_OR(notifyRemoveBreakpointFailed(id); return);
447
448     lldb::SBBreakpoint llbp = m_breakpoints.take(id);
449     llbp.SetEnabled(false);
450     notifyRemoveBreakpointOk(id);
451 }
452
453 void LldbEngineGuest::changeBreakpoint(BreakpointId id,
454         const Internal::BreakpointParameters &bp)
455 {
456     DEBUG_FUNC_ENTER;
457
458     // TODO
459     Q_UNUSED(id);
460     Q_UNUSED(bp);
461 }
462
463 void LldbEngineGuest::selectThread(qint64 token)
464 {
465     DEBUG_FUNC_ENTER;
466     SYNC_INFERIOR_OR(return);
467
468     m_frame_to_file.clear();
469     for (uint i = 0; i < m_process->GetNumThreads(); i++) {
470         lldb::SBThread t = m_process->GetThreadAtIndex(i);
471         if (t.GetThreadID() == token) {
472             m_currentThread = t;
473             StackFrames frames;
474             int firstResolvableFrame = -1;
475             for (uint j = 0; j < t.GetNumFrames(); j++) {
476                 lldb::SBFrame fr = t.GetFrameAtIndex(j);
477                 if (!fr.IsValid()) {
478                     qDebug("warning: frame %i is garbage", j);
479                     continue;
480                 }
481                 lldb::SBSymbolContext context =
482                     fr.GetSymbolContext(lldb::eSymbolContextEverything);
483                 lldb::SBSymbol sym = fr.GetSymbol();
484                 lldb::SBFunction func = fr.GetFunction();
485                 lldb::SBCompileUnit tu = fr.GetCompileUnit();
486                 lldb::SBModule module = fr.GetModule();
487                 lldb::SBBlock block = fr.GetBlock();
488                 lldb::SBBlock fblock = fr.GetFrameBlock();
489                 lldb::SBLineEntry le = fr.GetLineEntry();
490                 lldb::SBValueList values = fr.GetVariables(true, true, true, false);
491 #if 0
492                 qDebug()<<"\tframe "<<fr.GetFrameID();
493                 qDebug() << "\t\tPC:     " << ("0x" + QByteArray::number(
494                             fr.GetPCAddress().GetLoadAddress(*m_target), 16)).data();
495                 qDebug() << "\t\tFP:     " << ("0x" + QByteArray::number(fr.GetFP(), 16)).data();
496                 qDebug() << "\t\tSP:     " << ("0x" + QByteArray::number(fr.GetSP(), 16)).data();
497                 qDebug() << "\t\tsymbol:  " << sym.IsValid() << sym.GetName() << sym.GetMangledName();
498                 qDebug() << "\t\tfunction:" << func.IsValid();
499                 qDebug() << "\t\ttu:      " << tu.IsValid();
500                 if (tu.IsValid()) {
501
502                 }
503                 qDebug() << "\t\tmodule:  " << module.IsValid() << module.GetFileSpec().IsValid()
504                     << module.GetFileSpec().GetFilename();
505                 qDebug() << "\t\tblock:   " << block.IsValid() << block.GetInlinedName();
506                 qDebug() << "\t\tfblock:  " << block.IsValid() << block.GetInlinedName();
507                 qDebug() << "\t\tle:      " << le.IsValid() << le.GetLine()<<le.GetColumn();
508                 qDebug() << "\t\tvalues:  "<<values.IsValid() << values.GetSize();
509                 qDebug() << "\t\tcontext: " << context.IsValid();
510                 qDebug() << "\t\t\tmodule:   " << context.GetModule().IsValid();
511                 qDebug() << "\t\t\tfunction: " << context.GetFunction().IsValid();
512                 qDebug() << "\t\t\tblock:    " << context.GetBlock().IsValid();
513                 qDebug() << "\t\t\tle:       " << context.GetLineEntry().IsValid();
514                 qDebug() << "\t\t\tsymbol:   " << context.GetSymbol().IsValid();
515 //            qDebug() << "\t\tdisassemly -->\n" << fr.Disassemble() << "<--";
516 #endif
517
518                 QString sourceFile;
519                 QString sourceFilePath;
520                 int lineNumber = 0;
521                 if (le.IsValid()) {
522                     lineNumber = le.GetLine();
523                     if (le.GetFileSpec().IsValid()) {
524                         sourceFile = QString::fromLocal8Bit(le.GetFileSpec().GetFilename());
525                         sourceFilePath = QString::fromLocal8Bit(le.GetFileSpec().GetDirectory())
526                             + QLatin1String("/") + sourceFile;
527                         if (firstResolvableFrame < 0)
528                             firstResolvableFrame = j;
529                     }
530                 }
531                 sourceFilePath = QFileInfo(sourceFilePath).canonicalFilePath();
532
533                 QString functionName;
534                 if (func.IsValid())
535                     functionName = QString::fromLocal8Bit(func.GetName());
536                 else
537                     functionName = QString::fromLocal8Bit(sym.GetName());
538
539                 StackFrame frame;
540                 frame.level = fr.GetFrameID();
541                 if (func.IsValid())
542                     frame.function = QString::fromLocal8Bit(func.GetName());
543                 else
544                     frame.function = QString::fromLocal8Bit(sym.GetName());
545                 frame.from = QString::fromLocal8Bit(module.GetFileSpec().GetFilename());
546                 frame.address = fr.GetPCAddress().GetLoadAddress(*m_target);
547                 frame.line = lineNumber;
548                 frame.file = sourceFilePath;
549                 frame.usable = QFileInfo(frame.file).isReadable();
550                 frames.append(frame);
551                 m_frame_to_file.insert(j, frame.file);
552             }
553             currentThreadChanged(token);
554             listFrames(frames);
555             activateFrame(firstResolvableFrame > -1 ? firstResolvableFrame : 0);
556             return;
557         }
558     }
559 }
560
561 void LldbEngineGuest::updateThreads()
562 {
563     DEBUG_FUNC_ENTER;
564     SYNC_INFERIOR_OR(return);
565
566    /* There is no  way to find the StopReason of a _process_
567      * We try to emulate gdb here, by assuming there must be exactly one 'guilty' thread.
568      * However, if there are no threads at all, it must be that the process
569      * no longer exists. Let's tear down the whole session.
570      */
571     if (m_process->GetNumThreads() < 1) {
572         notifyEngineSpontaneousShutdown();
573         m_process->Kill();
574         m_process->Destroy();
575     }
576
577     Threads threads;
578     for (uint i = 0; i < m_process->GetNumThreads(); i++) {
579         lldb::SBThread t = m_process->GetThreadAtIndex(i);
580         if (!t.IsValid()) {
581                 qDebug("warning: thread %i is garbage", i);
582                 continue;
583         }
584         ThreadData thread;
585         thread.id = t.GetThreadID();
586         thread.targetId = QString::number(t.GetThreadID());
587         thread.core.clear();
588         thread.state = QString::number(t.GetStopReason());
589
590         switch (t.GetStopReason()) {
591             case lldb::eStopReasonInvalid:
592             case lldb::eStopReasonNone:
593             case lldb::eStopReasonTrace:
594                 thread.state = QLatin1String("running");
595                 break;
596             case lldb::eStopReasonBreakpoint:
597             case lldb::eStopReasonWatchpoint:
598                 showStatusMessage(QLatin1String("hit breakpoint"));
599                 thread.state = QLatin1String("hit breakpoint");
600                 if (m_currentThread.GetThreadID() != t.GetThreadID()) {
601                     m_currentThread = t;
602                     currentThreadChanged(t.GetThreadID());
603                     m_relistFrames = true;
604                 }
605                 break;
606             case lldb::eStopReasonSignal:
607                 showStatusMessage(QLatin1String("stopped"));
608                 thread.state = QLatin1String("stopped");
609                 if (m_currentThread.GetThreadID() != t.GetThreadID()) {
610                     m_currentThread = t;
611                     currentThreadChanged(t.GetThreadID());
612                     m_relistFrames = true;
613                 }
614                 break;
615             case lldb::eStopReasonException:
616                 showStatusMessage(QLatin1String("application crashed."));
617                 thread.state = QLatin1String("crashed");
618                 if (m_currentThread.GetThreadID() != t.GetThreadID()) {
619                     m_currentThread = t;
620                     currentThreadChanged(t.GetThreadID());
621                     m_relistFrames = true;
622                 }
623                 break;
624             case lldb::eStopReasonPlanComplete:
625                 thread.state = QLatin1String("crazy things happened");
626                 break;
627         };
628
629         thread.lineNumber = 0;
630         thread.name = QString::fromLocal8Bit(t.GetName());
631
632         lldb::SBFrame fr = t.GetFrameAtIndex(0);
633         if (!fr.IsValid()) {
634             qDebug("warning: frame 0 is garbage");
635             continue;
636         }
637         lldb::SBSymbolContext context = fr.GetSymbolContext(lldb::eSymbolContextEverything);
638         lldb::SBSymbol sym = fr.GetSymbol();
639         lldb::SBFunction func = fr.GetFunction();
640         lldb::SBLineEntry le = fr.GetLineEntry();
641         QString sourceFile;
642         QString sourceFilePath;
643         int lineNumber = 0;
644         if (le.IsValid()) {
645             lineNumber = le.GetLine();
646             if (le.GetFileSpec().IsValid()) {
647                 sourceFile = QString::fromLocal8Bit(le.GetFileSpec().GetFilename());
648                 sourceFilePath = QString::fromLocal8Bit(le.GetFileSpec().GetDirectory())
649                     + QLatin1String("/") + sourceFile;
650             }
651         }
652         QString functionName;
653         if (func.IsValid())
654             functionName = QString::fromLocal8Bit(func.GetName());
655         else
656             functionName = QString::fromLocal8Bit(sym.GetName());
657
658         lldb::SBValueList values = fr.GetVariables(true, true, false, false);
659         thread.fileName = sourceFile;
660         thread.function = functionName;
661         thread.address = fr.GetPCAddress().GetLoadAddress(*m_target);
662         thread.lineNumber = lineNumber;
663         threads.append(thread);
664     }
665     listThreads(threads);
666     if (m_relistFrames) {
667         selectThread(m_currentThread.GetThreadID());
668         m_relistFrames = false;
669     }
670 }
671
672 void LldbEngineGuest::lldbEvent(lldb::SBEvent *ev)
673 {
674     qDebug() << "lldbevent" << ev->GetType() <<
675          m_process->GetState() << (int)state();
676
677     uint32_t etype = ev->GetType();
678     switch (etype) {
679         // ProcessEvent
680         case 1:
681             switch (m_process->GetState()) {
682                 case lldb::eStateRunning: // 5
683                     if (!m_running) {
684                         m_running = true;
685                     }
686                     notifyInferiorPid(m_process->GetProcessID());
687                     switch (state()) {
688                         case EngineRunRequested:
689                             notifyEngineRunAndInferiorRunOk();
690                             break;
691                         case InferiorRunRequested:
692                             notifyInferiorRunOk();
693                             break;
694                         case InferiorStopOk:
695                             notifyInferiorRunRequested();
696                             notifyInferiorRunOk();
697                             break;
698                         default:
699                             break;
700                     }
701                     break;
702                 case lldb::eStateExited: // 9
703                     if (m_running) {
704                         m_running = false;
705                     }
706                     switch (state()) {
707                         case InferiorShutdownRequested:
708                             notifyInferiorShutdownOk();
709                             break;
710                         case InferiorRunOk:
711                             m_relistFrames = true;
712                             updateThreads();
713                             notifyEngineSpontaneousShutdown();
714                             m_process->Kill();
715                             m_process->Destroy();
716                             break;
717                         default:
718                             updateThreads();
719                             break;
720                     }
721                     break;
722                 case lldb::eStateStopped: // 4
723                     if (m_running) {
724                         m_running = false;
725                     }
726                     switch (state()) {
727                         case InferiorShutdownRequested:
728                             notifyInferiorShutdownOk();
729                             break;
730                         case InferiorRunOk:
731                             m_relistFrames = true;
732                             updateThreads();
733                             notifyInferiorSpontaneousStop();
734                             // fall
735                         default:
736                             m_relistFrames = true;
737                             updateThreads();
738                             break;
739                     }
740                     break;
741                 case lldb::eStateCrashed: // 7
742                     if (m_running) {
743                         m_running = false;
744                     }
745                     switch (state()) {
746                         case InferiorShutdownRequested:
747                             notifyInferiorShutdownOk();
748                             break;
749                         case InferiorRunOk:
750                             m_relistFrames = true;
751                             updateThreads();
752                             notifyInferiorSpontaneousStop();
753                             break;
754                         default:
755                             break;
756                     }
757                     break;
758                 default:
759                     qDebug("unexpected ProcessEvent");
760                     break;
761             }
762             break;;
763         default:
764             break;;
765     };
766 }
767
768
769 } // namespace Internal
770 } // namespace Debugger