pdbengine.cpp 21.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
hjk's avatar
hjk committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
hjk's avatar
hjk committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
hjk's avatar
hjk committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
hjk's avatar
hjk committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30 31 32

#include "pdbengine.h"

33 34 35 36 37 38 39 40
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerdialogs.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/debuggertooltipmanager.h>
Christian Kandeler's avatar
Christian Kandeler committed
41
#include <debugger/threaddata.h>
42

43 44 45 46 47 48 49
#include <debugger/breakhandler.h>
#include <debugger/moduleshandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/sourceutils.h>
#include <debugger/watchhandler.h>
#include <debugger/watchutils.h>
50

hjk's avatar
hjk committed
51 52
#include <utils/qtcassert.h>

53
#include <texteditor/texteditor.h>
54
#include <coreplugin/idocument.h>
hjk's avatar
hjk committed
55
#include <coreplugin/icore.h>
56
#include <coreplugin/messagebox.h>
hjk's avatar
hjk committed
57

58 59 60 61 62 63
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QVariant>
hjk's avatar
hjk committed
64

hjk's avatar
hjk committed
65
using namespace Core;
hjk's avatar
hjk committed
66 67 68 69

namespace Debugger {
namespace Internal {

70
PdbEngine::PdbEngine(const DebuggerStartParameters &startParameters)
71
    : DebuggerEngine(startParameters)
Friedemann Kleint's avatar
Friedemann Kleint committed
72 73 74
{
    setObjectName(QLatin1String("PdbEngine"));
}
hjk's avatar
hjk committed
75

76
void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
hjk's avatar
hjk committed
77
{
78 79
    if (!(languages & CppLanguage))
        return;
80 81
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
    //XSDEBUG("PdbEngine::executeDebuggerCommand:" << command);
hjk's avatar
hjk committed
82
    if (state() == DebuggerNotReady) {
83
        showMessage(_("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: ") + command);
hjk's avatar
hjk committed
84 85
        return;
    }
86
    QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
hjk's avatar
hjk committed
87
    postDirectCommand(command.toLatin1());
88 89 90 91 92 93
}

void PdbEngine::postDirectCommand(const QByteArray &command)
{
    QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
    showMessage(_(command), LogInput);
hjk's avatar
hjk committed
94
    m_pdbProc.write(command + '\n');
hjk's avatar
hjk committed
95 96
}

97 98 99
void PdbEngine::runCommand(const DebuggerCommand &cmd)
{
    QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
100
    QByteArray command = "qdebug('" + cmd.function + "',{" + cmd.args + "})";
101 102 103 104
    showMessage(_(command), LogInput);
    m_pdbProc.write(command + '\n');
}

hjk's avatar
hjk committed
105
void PdbEngine::shutdownInferior()
hjk's avatar
hjk committed
106
{
hjk's avatar
hjk committed
107 108
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
    notifyInferiorShutdownOk();
hjk's avatar
hjk committed
109 110
}

hjk's avatar
hjk committed
111
void PdbEngine::shutdownEngine()
hjk's avatar
hjk committed
112
{
hjk's avatar
hjk committed
113
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
114 115 116
    m_pdbProc.kill();
}

hjk's avatar
hjk committed
117
void PdbEngine::setupEngine()
hjk's avatar
hjk committed
118
{
hjk's avatar
hjk committed
119
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
120

121
    m_pdb = _("python");
122
    showMessage(_("STARTING PDB ") + m_pdb);
hjk's avatar
hjk committed
123

124 125 126 127 128 129 130 131 132
    connect(&m_pdbProc, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
        this, &PdbEngine::handlePdbError);
    connect(&m_pdbProc, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
        this, &PdbEngine::handlePdbFinished);
    connect(&m_pdbProc, &QProcess::readyReadStandardOutput,
        this, &PdbEngine::readPdbStandardOutput);
    connect(&m_pdbProc, &QProcess::readyReadStandardError,
        this, &PdbEngine::readPdbStandardError);

133
    m_pdbProc.start(m_pdb, QStringList() << _("-i"));
hjk's avatar
hjk committed
134 135

    if (!m_pdbProc.waitForStarted()) {
136
        const QString msg = tr("Unable to start pdb \"%1\": %2")
hjk's avatar
hjk committed
137
            .arg(m_pdb, m_pdbProc.errorString());
138
        notifyEngineSetupFailed();
139
        showMessage(_("ADAPTER START FAILED"));
hjk's avatar
hjk committed
140 141
        if (!msg.isEmpty())
            ICore::showWarningWithOptions(tr("Adapter start failed"), msg);
142
        notifyEngineSetupFailed();
hjk's avatar
hjk committed
143 144
        return;
    }
145
    notifyEngineSetupOk();
hjk's avatar
hjk committed
146 147 148 149
}

void PdbEngine::setupInferior()
{
hjk's avatar
hjk committed
150
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
151

152
    QString fileName = mainPythonFile();
153 154
    QFile scriptFile(fileName);
    if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
hjk's avatar
hjk committed
155
        AsynchronousMessageBox::critical(tr("Python Error"),
156 157 158 159 160 161
            _("Cannot open script file %1:\n%2").
               arg(fileName, scriptFile.errorString()));
        notifyInferiorSetupFailed();
        return;
    }
    notifyInferiorSetupOk();
hjk's avatar
hjk committed
162 163
}

164 165 166 167 168
QString PdbEngine::mainPythonFile() const
{
    return QFileInfo(startParameters().processArgs).absoluteFilePath();
}

hjk's avatar
hjk committed
169
void PdbEngine::runEngine()
hjk's avatar
hjk committed
170
{
171
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
hjk's avatar
hjk committed
172
    showStatusMessage(tr("Running requested..."), 5000);
hjk's avatar
hjk committed
173
    const QByteArray dumperSourcePath = ICore::resourcePath().toLocal8Bit() + "/debugger/";
174
    postDirectCommand("import sys");
175
    postDirectCommand("sys.argv.append('" + mainPythonFile().toLocal8Bit() + "')");
176
    postDirectCommand("execfile('/usr/bin/pdb')");
177
    postDirectCommand("execfile('" + dumperSourcePath + "pdbbridge.py')");
178 179 180
    attemptBreakpointSynchronization();
    notifyEngineRunAndInferiorStopOk();
    continueInferior();
hjk's avatar
hjk committed
181 182 183 184
}

void PdbEngine::interruptInferior()
{
185
    notifyInferiorStopOk();
hjk's avatar
hjk committed
186 187 188 189
}

void PdbEngine::executeStep()
{
190
    resetLocation();
191 192
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
193
    postDirectCommand("step");
hjk's avatar
hjk committed
194 195 196 197
}

void PdbEngine::executeStepI()
{
198
    resetLocation();
199 200
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
201
    postDirectCommand("step");
hjk's avatar
hjk committed
202 203 204 205
}

void PdbEngine::executeStepOut()
{
206
    resetLocation();
207 208
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
209
    postDirectCommand("return");
hjk's avatar
hjk committed
210 211 212 213
}

void PdbEngine::executeNext()
{
214
    resetLocation();
215 216
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
217
    postDirectCommand("next");
hjk's avatar
hjk committed
218 219 220 221
}

void PdbEngine::executeNextI()
{
222
    resetLocation();
223 224
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
225
    postDirectCommand("next");
hjk's avatar
hjk committed
226 227 228 229
}

void PdbEngine::continueInferior()
{
230
    resetLocation();
231 232
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
233
    // Callback will be triggered e.g. when breakpoint is hit.
hjk's avatar
hjk committed
234
    postDirectCommand("continue");
hjk's avatar
hjk committed
235 236
}

237
void PdbEngine::executeRunToLine(const ContextData &data)
hjk's avatar
hjk committed
238
{
239
    Q_UNUSED(data)
hjk's avatar
hjk committed
240
    QTC_CHECK("FIXME:  PdbEngine::runToLineExec()" && false);
hjk's avatar
hjk committed
241 242 243 244 245
}

void PdbEngine::executeRunToFunction(const QString &functionName)
{
    Q_UNUSED(functionName)
hjk's avatar
hjk committed
246
    QTC_CHECK("FIXME:  PdbEngine::runToFunctionExec()" && false);
hjk's avatar
hjk committed
247 248
}

249
void PdbEngine::executeJumpToLine(const ContextData &data)
hjk's avatar
hjk committed
250
{
251
    Q_UNUSED(data)
hjk's avatar
hjk committed
252
    QTC_CHECK("FIXME:  PdbEngine::jumpToLineExec()" && false);
hjk's avatar
hjk committed
253 254 255 256
}

void PdbEngine::activateFrame(int frameIndex)
{
257
    resetLocation();
hjk's avatar
hjk committed
258
    if (state() != InferiorStopOk && state() != InferiorUnrunnable)
hjk's avatar
hjk committed
259 260
        return;

261 262
    StackHandler *handler = stackHandler();
    int oldIndex = handler->currentIndex();
hjk's avatar
hjk committed
263

264
    //if (frameIndex == handler->stackSize()) {
hjk's avatar
hjk committed
265 266 267 268
    //    reloadFullStack();
    //    return;
    //}

269
    QTC_ASSERT(frameIndex < handler->stackSize(), return);
hjk's avatar
hjk committed
270 271 272 273 274

    if (oldIndex != frameIndex) {
        // Assuming the command always succeeds this saves a roundtrip.
        // Otherwise the lines below would need to get triggered
        // after a response to this -stack-select-frame here.
275
        handler->setCurrentIndex(frameIndex);
hjk's avatar
hjk committed
276
        //postDirectCommand("-stack-select-frame " + QByteArray::number(frameIndex));
hjk's avatar
hjk committed
277
    }
278
    gotoLocation(handler->currentFrame());
hjk's avatar
hjk committed
279 280
}

hjk's avatar
hjk committed
281
void PdbEngine::selectThread(ThreadId threadId)
hjk's avatar
hjk committed
282
{
hjk's avatar
hjk committed
283
    Q_UNUSED(threadId)
hjk's avatar
hjk committed
284 285
}

286
bool PdbEngine::acceptsBreakpoint(Breakpoint bp) const
hjk's avatar
hjk committed
287
{
288
    const QString fileName = bp.fileName();
hjk's avatar
hjk committed
289 290 291
    return fileName.endsWith(QLatin1String(".py"));
}

292
void PdbEngine::insertBreakpoint(Breakpoint bp)
hjk's avatar
hjk committed
293
{
294 295
    QTC_CHECK(bp.state() == BreakpointInsertRequested);
    bp.notifyBreakpointInsertProceeding();
hjk's avatar
hjk committed
296 297

    QByteArray loc;
298 299
    if (bp.type() == BreakpointByFunction)
        loc = bp.functionName().toLatin1();
hjk's avatar
hjk committed
300
    else
301 302
        loc = bp.fileName().toLocal8Bit() + ':'
         + QByteArray::number(bp.lineNumber());
hjk's avatar
hjk committed
303

hjk's avatar
hjk committed
304
    postDirectCommand("break " + loc);
hjk's avatar
hjk committed
305 306
}

307
void PdbEngine::removeBreakpoint(Breakpoint bp)
hjk's avatar
hjk committed
308
{
309 310 311 312
    QTC_CHECK(bp.state() == BreakpointRemoveRequested);
    bp.notifyBreakpointRemoveProceeding();
    BreakpointResponse br = bp.response();
    showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
hjk's avatar
hjk committed
313
    postDirectCommand("clear " + br.id.toByteArray());
hjk's avatar
hjk committed
314
    // Pretend it succeeds without waiting for response.
315
    bp.notifyBreakpointRemoveOk();
hjk's avatar
hjk committed
316 317
}

hjk's avatar
hjk committed
318 319 320 321 322 323 324 325 326 327 328
void PdbEngine::loadSymbols(const QString &moduleName)
{
    Q_UNUSED(moduleName)
}

void PdbEngine::loadAllSymbols()
{
}

void PdbEngine::reloadModules()
{
hjk's avatar
hjk committed
329
    runCommand("listModules");
hjk's avatar
hjk committed
330 331
}

hjk's avatar
hjk committed
332
void PdbEngine::refreshModules(const GdbMi &modules)
hjk's avatar
hjk committed
333
{
334 335
    ModulesHandler *handler = modulesHandler();
    handler->beginUpdateAll();
hjk's avatar
hjk committed
336
    foreach (const GdbMi &item, modules.children()) {
hjk's avatar
hjk committed
337
        Module module;
338 339
        module.moduleName = _(item["name"].data());
        QString path = _(item["value"].data());
hjk's avatar
hjk committed
340 341 342 343 344 345 346 347 348 349
        int pos = path.indexOf(_("' from '"));
        if (pos != -1) {
            path = path.mid(pos + 8);
            if (path.size() >= 2)
                path.chop(2);
        } else if (path.startsWith(_("<module '"))
                && path.endsWith(_("' (built-in)>"))) {
            path = _("(builtin)");
        }
        module.modulePath = path;
350
        handler->updateModule(module);
hjk's avatar
hjk committed
351
    }
352
    handler->endUpdateAll();
hjk's avatar
hjk committed
353 354
}

hjk's avatar
hjk committed
355
void PdbEngine::requestModuleSymbols(const QString &moduleName)
hjk's avatar
hjk committed
356
{
hjk's avatar
hjk committed
357 358 359
    DebuggerCommand cmd("listSymbols");
    cmd.arg("module", moduleName);
    runCommand(cmd);
hjk's avatar
hjk committed
360 361
}

hjk's avatar
hjk committed
362
void PdbEngine::refreshSymbols(const GdbMi &symbols)
hjk's avatar
hjk committed
363
{
hjk's avatar
hjk committed
364 365 366
    QString moduleName = symbols["module"].toUtf8();
    Symbols syms;
    foreach (const GdbMi &item, symbols["symbols"].children()) {
hjk's avatar
hjk committed
367
        Symbol symbol;
hjk's avatar
hjk committed
368 369
        symbol.name = item["name"].toUtf8();
        syms.append(symbol);
hjk's avatar
hjk committed
370
    }
hjk's avatar
hjk committed
371
    Internal::showModuleSymbols(moduleName, syms);
hjk's avatar
hjk committed
372
}
hjk's avatar
hjk committed
373

374
bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *,
hjk's avatar
hjk committed
375
    const DebuggerToolTipContext &ctx)
hjk's avatar
hjk committed
376
{
377
    if (state() != InferiorStopOk)
378
        return false;
hjk's avatar
hjk committed
379

380 381
    DebuggerCommand cmd("evaluateTooltip");
    ctx.appendFormatRequest(&cmd);
hjk's avatar
hjk committed
382
    watchHandler()->appendFormatRequests(&cmd);
383 384
    runCommand(cmd);
    return true;
hjk's avatar
hjk committed
385 386
}

387 388 389 390 391 392 393 394
void PdbEngine::assignValueInDebugger(const WatchData *, const QString &expression, const QVariant &value)
{
    //DebuggerCommand cmd("assignValue");
    //cmd.arg("expression", expression);
    //cmd.arg("value", value.toString());
    //runCommand(cmd);
    QByteArray exp = expression.toUtf8();
    postDirectCommand("global " + exp + ';' + exp + "=" + value.toString().toUtf8());
hjk's avatar
hjk committed
395 396 397
    updateLocals();
}

hjk's avatar
hjk committed
398
void PdbEngine::updateWatchData(const WatchData &data)
hjk's avatar
hjk committed
399 400 401 402 403 404 405
{
    Q_UNUSED(data);
    updateAll();
}

void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
406
    qDebug() << "HANDLE PDB ERROR";
407
    showMessage(_("HANDLE PDB ERROR"));
hjk's avatar
hjk committed
408 409 410 411 412 413 414 415
    switch (error) {
    case QProcess::Crashed:
        break; // will get a processExited() as well
    // impossible case QProcess::FailedToStart:
    case QProcess::ReadError:
    case QProcess::WriteError:
    case QProcess::Timedout:
    default:
416
        //setState(EngineShutdownRequested, true);
hjk's avatar
hjk committed
417
        m_pdbProc.kill();
hjk's avatar
hjk committed
418
        AsynchronousMessageBox::critical(tr("Pdb I/O Error"), errorMessage(error));
hjk's avatar
hjk committed
419 420 421 422 423 424 425 426 427
        break;
    }
}

QString PdbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
            return tr("The Pdb process failed to start. Either the "
428
                "invoked program \"%1\" is missing, or you may have insufficient "
hjk's avatar
hjk committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
                "permissions to invoke the program.")
                .arg(m_pdb);
        case QProcess::Crashed:
            return tr("The Pdb process crashed some time after starting "
                "successfully.");
        case QProcess::Timedout:
            return tr("The last waitFor...() function timed out. "
                "The state of QProcess is unchanged, and you can try calling "
                "waitFor...() again.");
        case QProcess::WriteError:
            return tr("An error occurred when attempting to write "
                "to the Pdb process. For example, the process may not be running, "
                "or it may have closed its input channel.");
        case QProcess::ReadError:
            return tr("An error occurred when attempting to read from "
                "the Pdb process. For example, the process may not be running.");
        default:
446
            return tr("An unknown error in the Pdb process occurred.") + QLatin1Char(' ');
hjk's avatar
hjk committed
447 448 449 450 451
    }
}

void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{
452
    qDebug() << "PDB FINISHED";
453
    showMessage(_("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
454
    notifyEngineSpontaneousShutdown();
hjk's avatar
hjk committed
455 456 457 458 459
}

void PdbEngine::readPdbStandardError()
{
    QByteArray err = m_pdbProc.readAllStandardError();
460 461 462 463
    qDebug() << "\nPDB STDERR" << err;
    //qWarning() << "Unexpected pdb stderr:" << err;
    //showMessage(_("Unexpected pdb stderr: " + err));
    //handleOutput(err);
hjk's avatar
hjk committed
464 465 466 467
}

void PdbEngine::readPdbStandardOutput()
{
468 469 470 471 472 473 474 475 476
    QByteArray out = m_pdbProc.readAllStandardOutput();
    qDebug() << "\nPDB STDOUT" << out;
    handleOutput(out);
}

void PdbEngine::handleOutput(const QByteArray &data)
{
    //qDebug() << "READ: " << data;
    m_inbuffer.append(data);
477
    qDebug() << "BUFFER FROM: '" << m_inbuffer << '\'';
478 479 480 481 482 483 484
    while (true) {
        int pos = m_inbuffer.indexOf("(Pdb)");
        if (pos == -1)
            pos = m_inbuffer.indexOf(">>>");
        if (pos == -1)
            break;
        QByteArray response = m_inbuffer.left(pos).trimmed();
hjk's avatar
hjk committed
485
        m_inbuffer = m_inbuffer.mid(pos + 6);
hjk's avatar
hjk committed
486
        handleOutput2(response);
487
    }
488
    qDebug() << "BUFFER LEFT: '" << m_inbuffer << '\'';
489 490 491 492 493
    //m_inbuffer.clear();
}

void PdbEngine::handleOutput2(const QByteArray &data)
{
494 495 496
    QByteArray lineContext;
    foreach (QByteArray line, data.split('\n')) {

hjk's avatar
hjk committed
497 498
        GdbMi item;
        item.fromString(line);
hjk's avatar
hjk committed
499

500 501 502
        showMessage(_("LINE: " + line));

        if (line.startsWith("stack={")) {
hjk's avatar
hjk committed
503
            refreshStack(item);
hjk's avatar
hjk committed
504
        } else if (line.startsWith("data={")) {
hjk's avatar
hjk committed
505
            refreshLocals(item);
hjk's avatar
hjk committed
506
        } else if (line.startsWith("modules=[")) {
hjk's avatar
hjk committed
507
            refreshModules(item);
hjk's avatar
hjk committed
508
        } else if (line.startsWith("symbols={")) {
hjk's avatar
hjk committed
509
            refreshSymbols(item);
hjk's avatar
hjk committed
510
        } else if (line.startsWith("Breakpoint")) {
hjk's avatar
hjk committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
            int pos1 = line.indexOf(" at ");
            QTC_ASSERT(pos1 != -1, continue);
            QByteArray bpnr = line.mid(11, pos1 - 11);
            int pos2 = line.lastIndexOf(':');
            QTC_ASSERT(pos2 != -1, continue);
            QByteArray fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
            QByteArray lineNumber = line.mid(pos2 + 1);
            BreakpointResponse br;
            br.id = BreakpointResponseId(bpnr);
            br.fileName = _(fileName);
            br.lineNumber = lineNumber.toInt();
            Breakpoint bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
            if (bp.isValid()) {
                bp.setResponse(br);
                QTC_CHECK(!bp.needsChange());
                bp.notifyBreakpointInsertOk();
            }
hjk's avatar
hjk committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
        } else {
            if (line.startsWith("> /")) {
                lineContext = line;
                int pos1 = line.indexOf('(');
                int pos2 = line.indexOf(')', pos1);
                if (pos1 != -1 && pos2 != -1) {
                    int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
                    QByteArray fileName = line.mid(2, pos1 - 2);
                    qDebug() << " " << pos1 << pos2 << lineNumber << fileName
                             << line.mid(pos1 + 1, pos2 - pos1 - 1);
                    StackFrame frame;
                    frame.file = _(fileName);
                    frame.line = lineNumber;
                    if (state() == InferiorRunOk) {
                        showMessage(QString::fromLatin1("STOPPED AT: %1:%2").arg(frame.file).arg(frame.line));
                        gotoLocation(frame);
                        notifyInferiorSpontaneousStop();
                        updateAll();
                        continue;
                    }
548 549
                }
            }
hjk's avatar
hjk committed
550
            showMessage(_(" #### ... UNHANDLED"));
551
        }
hjk's avatar
hjk committed
552 553
    }
}
hjk's avatar
hjk committed
554

555
/*
hjk's avatar
hjk committed
556 557 558 559 560 561 562 563 564 565 566 567
void PdbEngine::handleResponse(const QByteArray &response0)
{
    QByteArray response = response0;
    qDebug() << "RESPONSE: '" << response << "'";
    if (response.startsWith("--Call--")) {
        qDebug() << "SKIPPING '--Call--' MARKER";
        response = response.mid(9);
    }
    if (response.startsWith("--Return--")) {
        qDebug() << "SKIPPING '--Return--' MARKER";
        response = response.mid(11);
    }
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
}
*/

void PdbEngine::refreshLocals(const GdbMi &vars)
{
    WatchHandler *handler = watchHandler();
    handler->resetValueCache();

    QSet<QByteArray> toDelete;
    foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2))
        toDelete.insert(item->d.iname);

    foreach (const GdbMi &child, vars.children()) {
        WatchItem *item = new WatchItem(child);
        handler->insertItem(item);
        toDelete.remove(item->d.iname);
    }

    handler->purgeOutdatedItems(toDelete);

    DebuggerToolTipManager::updateEngine(this);
}

void PdbEngine::refreshStack(const GdbMi &stack)
{
    StackHandler *handler = stackHandler();
    StackFrames frames;
    foreach (const GdbMi &item, stack["frames"].children()) {
        StackFrame frame;
        frame.level = item["level"].toInt();
        frame.file = item["file"].toUtf8();
        frame.function = item["func"].toUtf8();
        frame.from = item["func"].toUtf8();
        frame.line = item["line"].toInt();
        frame.address = item["addr"].toAddress();
        GdbMi usable = item["usable"];
        if (usable.isValid())
            frame.usable = usable.data().toInt();
        else
            frame.usable = QFileInfo(frame.file).isReadable();
        if (item["language"].data() == "js"
                || frame.file.endsWith(QLatin1String(".js"))
                || frame.file.endsWith(QLatin1String(".qml"))) {
            frame.language = QmlLanguage;
            frame.fixQmlFrame(startParameters());
hjk's avatar
hjk committed
613
        }
614
        frames.append(frame);
hjk's avatar
hjk committed
615
    }
616 617 618 619 620 621 622 623
    bool canExpand = stack["hasmore"].toInt();
    //action(ExpandStack)->setEnabled(canExpand);
    handler->setFrames(frames, canExpand);

    int index = stackHandler()->firstUsableIndex();
    handler->setCurrentIndex(index);
    if (index >= 0 && index < handler->stackSize())
        gotoLocation(handler->frameAt(index));
hjk's avatar
hjk committed
624 625 626
}

void PdbEngine::updateAll()
627
{
hjk's avatar
hjk committed
628
    runCommand("stackListFrames");
629
    updateLocals();
630 631 632
}

void PdbEngine::updateLocals()
hjk's avatar
hjk committed
633
{
634 635 636
    DebuggerCommand cmd("updateData");
    cmd.arg("nativeMixed", isNativeMixedActive());
    watchHandler()->appendFormatRequests(&cmd);
hjk's avatar
hjk committed
637

638 639 640 641 642 643 644 645
    const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
    cmd.arg("passexceptions", alwaysVerbose);
    cmd.arg("fancy", boolSetting(UseDebuggingHelpers));

    cmd.beginList("watchers");

    // Watchers
    QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
hjk's avatar
hjk committed
646 647
    while (it.hasNext()) {
        it.next();
648 649 650 651
        cmd.beginGroup();
        cmd.arg("iname", "watch." + QByteArray::number(it.value()));
        cmd.arg("exp", it.key().toHex());
        cmd.endGroup();
hjk's avatar
hjk committed
652 653
    }

654 655 656 657 658 659 660
    // Tooltips
    DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
    foreach (const DebuggerToolTipContext &p, toolTips) {
        cmd.beginGroup();
        cmd.arg("iname", p.iname);
        cmd.arg("exp", p.expression.toLatin1().toHex());
        cmd.endGroup();
hjk's avatar
hjk committed
661
    }
662

663 664 665 666 667 668 669
    cmd.endList();

    //cmd.arg("resultvarname", m_resultVarName);
    //m_lastDebuggableCommand = cmd;
    //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");

    runCommand(cmd);
hjk's avatar
hjk committed
670 671
}

672
bool PdbEngine::hasCapability(unsigned cap) const
hjk's avatar
hjk committed
673
{
hjk's avatar
hjk committed
674 675 676
    return cap & (ReloadModuleCapability
              | BreakConditionCapability
              | ShowModuleSymbolsCapability);
hjk's avatar
hjk committed
677 678
}

679
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &startParameters)
hjk's avatar
hjk committed
680
{
681
    return new PdbEngine(startParameters);
hjk's avatar
hjk committed
682 683 684 685
}

} // namespace Internal
} // namespace Debugger