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();
}

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

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

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

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

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

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

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

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

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

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

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

556
/*
hjk's avatar
hjk committed
557 558 559 560 561 562 563 564 565 566 567 568
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);
    }
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 613
}
*/

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

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

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

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

655 656 657 658 659 660 661
    // 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
662
    }
663

664 665 666 667 668 669 670
    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
671 672
}

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

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

} // namespace Internal
} // namespace Debugger