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>
41

42 43 44 45 46 47 48
#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>
49

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

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

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

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

namespace Debugger {
namespace Internal {

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

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

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

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

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

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

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

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

123 124 125 126 127 128 129 130 131
    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);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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.
274
        handler->setCurrentIndex(frameIndex);
hjk's avatar
hjk committed
275
        //postDirectCommand("-stack-select-frame " + QByteArray::number(frameIndex));
hjk's avatar
hjk committed
276
    }
277
    gotoLocation(handler->currentFrame());
hjk's avatar
hjk committed
278 279
}

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

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

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

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

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

306
void PdbEngine::removeBreakpoint(Breakpoint bp)
hjk's avatar
hjk committed
307
{
308 309 310 311
    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
312
    postDirectCommand("clear " + br.id.toByteArray());
hjk's avatar
hjk committed
313
    // Pretend it succeeds without waiting for response.
314
    bp.notifyBreakpointRemoveOk();
hjk's avatar
hjk committed
315 316
}

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

void PdbEngine::loadAllSymbols()
{
}

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

hjk's avatar
hjk committed
331
void PdbEngine::refreshModules(const GdbMi &modules)
hjk's avatar
hjk committed
332
{
333 334
    ModulesHandler *handler = modulesHandler();
    handler->beginUpdateAll();
hjk's avatar
hjk committed
335
    foreach (const GdbMi &item, modules.children()) {
hjk's avatar
hjk committed
336
        Module module;
337 338
        module.moduleName = _(item["name"].data());
        QString path = _(item["value"].data());
hjk's avatar
hjk committed
339 340 341 342 343 344 345 346 347 348
        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;
349
        handler->updateModule(module);
hjk's avatar
hjk committed
350
    }
351
    handler->endUpdateAll();
hjk's avatar
hjk committed
352 353
}

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

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

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

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

386 387 388 389 390 391 392 393
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
394 395 396
    updateLocals();
}

397
void PdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
hjk's avatar
hjk committed
398 399
{
    Q_UNUSED(data);
hjk's avatar
hjk committed
400
    Q_UNUSED(flags);
hjk's avatar
hjk committed
401 402 403 404 405
    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