pdbengine.cpp 21.1 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 <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("return");
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(const DebuggerToolTipContext &ctx)
hjk's avatar
hjk committed
374
{
375
    if (state() != InferiorStopOk)
376
        return false;
hjk's avatar
hjk committed
377

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

385
void PdbEngine::assignValueInDebugger(WatchItem *, const QString &expression, const QVariant &value)
386 387 388 389 390 391 392
{
    //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
393 394 395
    updateLocals();
}

396
void PdbEngine::updateWatchItem(WatchItem *item)
hjk's avatar
hjk committed
397
{
398
    Q_UNUSED(item);
hjk's avatar
hjk committed
399 400 401 402 403
    updateAll();
}

void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
404
    qDebug() << "HANDLE PDB ERROR";
405
    showMessage(_("HANDLE PDB ERROR"));
hjk's avatar
hjk committed
406 407 408 409 410 411 412 413
    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:
414
        //setState(EngineShutdownRequested, true);
hjk's avatar
hjk committed
415
        m_pdbProc.kill();
hjk's avatar
hjk committed
416
        AsynchronousMessageBox::critical(tr("Pdb I/O Error"), errorMessage(error));
hjk's avatar
hjk committed
417 418 419 420 421 422 423 424 425
        break;
    }
}

QString PdbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
            return tr("The Pdb process failed to start. Either the "
426
                "invoked program \"%1\" is missing, or you may have insufficient "
hjk's avatar
hjk committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
                "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:
444
            return tr("An unknown error in the Pdb process occurred.") + QLatin1Char(' ');
hjk's avatar
hjk committed
445 446 447 448 449
    }
}

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

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

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

void PdbEngine::handleOutput(const QByteArray &data)
{
    //qDebug() << "READ: " << data;
    m_inbuffer.append(data);
475
    qDebug() << "BUFFER FROM: '" << m_inbuffer << '\'';
476 477 478 479 480 481 482
    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
483
        m_inbuffer = m_inbuffer.mid(pos + 6);
hjk's avatar
hjk committed
484
        handleOutput2(response);
485
    }
486
    qDebug() << "BUFFER LEFT: '" << m_inbuffer << '\'';
487 488 489 490 491
    //m_inbuffer.clear();
}

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

hjk's avatar
hjk committed
495 496
        GdbMi item;
        item.fromString(line);
hjk's avatar
hjk committed
497

498 499 500
        showMessage(_("LINE: " + line));

        if (line.startsWith("stack={")) {
hjk's avatar
hjk committed
501
            refreshStack(item);
hjk's avatar
hjk committed
502
        } else if (line.startsWith("data={")) {
hjk's avatar
hjk committed
503
            refreshLocals(item);
hjk's avatar
hjk committed
504
        } else if (line.startsWith("modules=[")) {
hjk's avatar
hjk committed
505
            refreshModules(item);
hjk's avatar
hjk committed
506
        } else if (line.startsWith("symbols={")) {
hjk's avatar
hjk committed
507
            refreshSymbols(item);
hjk's avatar
hjk committed
508
        } else if (line.startsWith("Breakpoint")) {
hjk's avatar
hjk committed
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
            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
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
        } 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;
                    }
546 547
                }
            }
hjk's avatar
hjk committed
548
            showMessage(_(" #### ... UNHANDLED"));
549
        }
hjk's avatar
hjk committed
550 551
    }
}
hjk's avatar
hjk committed
552

553
/*
hjk's avatar
hjk committed
554 555 556 557 558 559 560 561 562 563 564 565
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);
    }
566 567 568 569 570 571 572 573 574
}
*/

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

    QSet<QByteArray> toDelete;
hjk's avatar
hjk committed
575
    foreach (WatchItem *item, handler->model()->itemsAtLevel<WatchItem *>(2))
576
        toDelete.insert(item->iname);
577 578 579 580

    foreach (const GdbMi &child, vars.children()) {
        WatchItem *item = new WatchItem(child);
        handler->insertItem(item);
581
        toDelete.remove(item->iname);
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
    }

    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
611
        }
612
        frames.append(frame);
hjk's avatar
hjk committed
613
    }
614 615 616 617 618 619 620 621
    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
622 623 624
}

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

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

636 637 638 639 640 641 642 643
    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
644 645
    while (it.hasNext()) {
        it.next();
646 647 648 649
        cmd.beginGroup();
        cmd.arg("iname", "watch." + QByteArray::number(it.value()));
        cmd.arg("exp", it.key().toHex());
        cmd.endGroup();
hjk's avatar
hjk committed
650 651
    }

652 653 654 655 656 657 658
    // 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
659
    }
660

661 662 663 664 665 666
    cmd.endList();

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

667
    watchHandler()->notifyUpdateStarted();
668
    runCommand(cmd);
hjk's avatar
hjk committed
669 670
}

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

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

} // namespace Internal
} // namespace Debugger