pdbengine.cpp 17.6 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
hjk's avatar
hjk committed
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
hjk's avatar
hjk committed
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
hjk's avatar
hjk committed
25 26 27

#include "pdbengine.h"

28 29 30 31 32 33 34
#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/debuggertooltipmanager.h>
Christian Kandeler's avatar
Christian Kandeler committed
35
#include <debugger/threaddata.h>
36

37 38
#include <debugger/breakhandler.h>
#include <debugger/moduleshandler.h>
39
#include <debugger/procinterrupt.h>
40 41 42 43 44
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/sourceutils.h>
#include <debugger/watchhandler.h>
#include <debugger/watchutils.h>
45

hjk's avatar
hjk committed
46
#include <utils/qtcassert.h>
hjk's avatar
hjk committed
47
#include <utils/qtcprocess.h>
hjk's avatar
hjk committed
48

49
#include <coreplugin/idocument.h>
hjk's avatar
hjk committed
50
#include <coreplugin/icore.h>
51
#include <coreplugin/messagebox.h>
hjk's avatar
hjk committed
52

53 54 55 56 57 58
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QVariant>
59
#include <QJsonArray>
hjk's avatar
hjk committed
60

hjk's avatar
hjk committed
61
using namespace Core;
hjk's avatar
hjk committed
62 63 64 65

namespace Debugger {
namespace Internal {

66
PdbEngine::PdbEngine()
Friedemann Kleint's avatar
Friedemann Kleint committed
67
{
68
    setObjectName("PdbEngine");
Friedemann Kleint's avatar
Friedemann Kleint committed
69
}
hjk's avatar
hjk committed
70

71
void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
hjk's avatar
hjk committed
72
{
73 74
    if (!(languages & CppLanguage))
        return;
75
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
hjk's avatar
hjk committed
76
    if (state() == DebuggerNotReady) {
hjk's avatar
hjk committed
77
        showMessage("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + command);
hjk's avatar
hjk committed
78 79
        return;
    }
80
    QTC_ASSERT(m_proc.state() == QProcess::Running, notifyEngineIll());
hjk's avatar
hjk committed
81
    postDirectCommand(command);
82 83
}

hjk's avatar
hjk committed
84
void PdbEngine::postDirectCommand(const QString &command)
85
{
86
    QTC_ASSERT(m_proc.state() == QProcess::Running, notifyEngineIll());
hjk's avatar
hjk committed
87 88
    showMessage(command, LogInput);
    m_proc.write(command.toUtf8() + '\n');
hjk's avatar
hjk committed
89 90
}

91 92
void PdbEngine::runCommand(const DebuggerCommand &cmd)
{
93 94 95 96
    if (state() == EngineSetupRequested) { // cmd has been triggered too early
        showMessage("IGNORED COMMAND: " + cmd.function);
        return;
    }
97
    QTC_ASSERT(m_proc.state() == QProcess::Running, notifyEngineIll());
hjk's avatar
hjk committed
98 99 100
    QString command = "qdebug('" + cmd.function + "'," + cmd.argsToPython() + ")";
    showMessage(command, LogInput);
    m_proc.write(command.toUtf8() + '\n');
101 102
}

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

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

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

hjk's avatar
hjk committed
119 120
    m_interpreter = runParameters().interpreter;
    QString bridge = ICore::resourcePath() + QLatin1String("/debugger/pdbbridge.py");
hjk's avatar
hjk committed
121

122
    connect(&m_proc, &QProcess::errorOccurred, this, &PdbEngine::handlePdbError);
123
    connect(&m_proc, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
124
        this, &PdbEngine::handlePdbFinished);
125
    connect(&m_proc, &QProcess::readyReadStandardOutput,
126
        this, &PdbEngine::readPdbStandardOutput);
127
    connect(&m_proc, &QProcess::readyReadStandardError,
128 129
        this, &PdbEngine::readPdbStandardError);

hjk's avatar
hjk committed
130 131 132
    QFile scriptFile(runParameters().mainScript);
    if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
        AsynchronousMessageBox::critical(tr("Python Error"),
hjk's avatar
hjk committed
133
            QString("Cannot open script file %1:\n%2").
hjk's avatar
hjk committed
134 135 136 137
               arg(scriptFile.fileName(), scriptFile.errorString()));
        notifyEngineSetupFailed();
    }

138
    QStringList args = {bridge, scriptFile.fileName()};
139
    args.append(Utils::QtcProcess::splitArgs(runParameters().inferior.workingDirectory));
hjk's avatar
hjk committed
140
    showMessage("STARTING " + m_interpreter + QLatin1Char(' ') + args.join(QLatin1Char(' ')));
141
    m_proc.setEnvironment(runParameters().debugger.environment.toStringList());
hjk's avatar
hjk committed
142
    m_proc.start(m_interpreter, args);
hjk's avatar
hjk committed
143

144
    if (!m_proc.waitForStarted()) {
145
        const QString msg = tr("Unable to start pdb \"%1\": %2")
hjk's avatar
hjk committed
146
            .arg(m_interpreter, m_proc.errorString());
147
        notifyEngineSetupFailed();
hjk's avatar
hjk committed
148
        showMessage("ADAPTER START FAILED");
hjk's avatar
hjk committed
149 150
        if (!msg.isEmpty())
            ICore::showWarningWithOptions(tr("Adapter start failed"), msg);
151
        notifyEngineSetupFailed();
hjk's avatar
hjk committed
152 153
        return;
    }
154
    notifyEngineSetupOk();
hjk's avatar
hjk committed
155 156 157 158
}

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

161
    notifyInferiorSetupOk();
hjk's avatar
hjk committed
162 163
}

hjk's avatar
hjk committed
164
void PdbEngine::runEngine()
hjk's avatar
hjk committed
165
{
166
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
hjk's avatar
hjk committed
167
    showStatusMessage(tr("Running requested..."), 5000);
168 169
    attemptBreakpointSynchronization();
    notifyEngineRunAndInferiorStopOk();
170
    updateAll();
hjk's avatar
hjk committed
171 172 173 174
}

void PdbEngine::interruptInferior()
{
175 176
    QString error;
    interruptProcess(m_proc.processId(), GdbEngineType, &error);
hjk's avatar
hjk committed
177 178 179 180
}

void PdbEngine::executeStep()
{
181 182
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
183
    postDirectCommand("step");
hjk's avatar
hjk committed
184 185 186 187
}

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

void PdbEngine::executeStepOut()
{
195 196
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
197
    postDirectCommand("return");
hjk's avatar
hjk committed
198 199 200 201
}

void PdbEngine::executeNext()
{
202 203
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
204
    postDirectCommand("next");
hjk's avatar
hjk committed
205 206 207 208
}

void PdbEngine::executeNextI()
{
209 210
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
211
    postDirectCommand("next");
hjk's avatar
hjk committed
212 213 214 215
}

void PdbEngine::continueInferior()
{
216 217
    notifyInferiorRunRequested();
    notifyInferiorRunOk();
hjk's avatar
hjk committed
218
    // Callback will be triggered e.g. when breakpoint is hit.
hjk's avatar
hjk committed
219
    postDirectCommand("continue");
hjk's avatar
hjk committed
220 221
}

222
void PdbEngine::executeRunToLine(const ContextData &data)
hjk's avatar
hjk committed
223
{
224
    Q_UNUSED(data)
hjk's avatar
hjk committed
225
    QTC_CHECK("FIXME:  PdbEngine::runToLineExec()" && false);
hjk's avatar
hjk committed
226 227 228 229 230
}

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

234
void PdbEngine::executeJumpToLine(const ContextData &data)
hjk's avatar
hjk committed
235
{
236
    Q_UNUSED(data)
hjk's avatar
hjk committed
237
    QTC_CHECK("FIXME:  PdbEngine::jumpToLineExec()" && false);
hjk's avatar
hjk committed
238 239 240 241
}

void PdbEngine::activateFrame(int frameIndex)
{
hjk's avatar
hjk committed
242
    if (state() != InferiorStopOk && state() != InferiorUnrunnable)
hjk's avatar
hjk committed
243 244
        return;

245 246
    StackHandler *handler = stackHandler();
    QTC_ASSERT(frameIndex < handler->stackSize(), return);
hjk's avatar
hjk committed
247
    handler->setCurrentIndex(frameIndex);
248
    gotoLocation(handler->currentFrame());
hjk's avatar
hjk committed
249
    updateLocals();
hjk's avatar
hjk committed
250 251
}

hjk's avatar
hjk committed
252
void PdbEngine::selectThread(ThreadId threadId)
hjk's avatar
hjk committed
253
{
hjk's avatar
hjk committed
254
    Q_UNUSED(threadId)
hjk's avatar
hjk committed
255 256
}

257
bool PdbEngine::acceptsBreakpoint(Breakpoint bp) const
hjk's avatar
hjk committed
258
{
259
    const QString fileName = bp.fileName();
hjk's avatar
hjk committed
260
    return fileName.endsWith(".py");
hjk's avatar
hjk committed
261 262
}

263
void PdbEngine::insertBreakpoint(Breakpoint bp)
hjk's avatar
hjk committed
264
{
265 266
    QTC_CHECK(bp.state() == BreakpointInsertRequested);
    bp.notifyBreakpointInsertProceeding();
hjk's avatar
hjk committed
267

hjk's avatar
hjk committed
268
    QString loc;
269
    if (bp.type() == BreakpointByFunction)
hjk's avatar
hjk committed
270
        loc = bp.functionName();
hjk's avatar
hjk committed
271
    else
hjk's avatar
hjk committed
272
        loc = bp.fileName() + ':' + QString::number(bp.lineNumber());
hjk's avatar
hjk committed
273

hjk's avatar
hjk committed
274
    postDirectCommand("break " + loc);
hjk's avatar
hjk committed
275 276
}

277
void PdbEngine::removeBreakpoint(Breakpoint bp)
hjk's avatar
hjk committed
278
{
279 280 281
    QTC_CHECK(bp.state() == BreakpointRemoveRequested);
    bp.notifyBreakpointRemoveProceeding();
    BreakpointResponse br = bp.response();
hjk's avatar
hjk committed
282 283
    showMessage(QString("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
    postDirectCommand("clear " + br.id.toString());
hjk's avatar
hjk committed
284
    // Pretend it succeeds without waiting for response.
285
    bp.notifyBreakpointRemoveOk();
hjk's avatar
hjk committed
286 287
}

hjk's avatar
hjk committed
288 289 290 291 292 293 294 295 296 297 298
void PdbEngine::loadSymbols(const QString &moduleName)
{
    Q_UNUSED(moduleName)
}

void PdbEngine::loadAllSymbols()
{
}

void PdbEngine::reloadModules()
{
299
    runCommand({"listModules"});
hjk's avatar
hjk committed
300 301
}

hjk's avatar
hjk committed
302
void PdbEngine::refreshModules(const GdbMi &modules)
hjk's avatar
hjk committed
303
{
304 305
    ModulesHandler *handler = modulesHandler();
    handler->beginUpdateAll();
hjk's avatar
hjk committed
306
    foreach (const GdbMi &item, modules.children()) {
hjk's avatar
hjk committed
307
        Module module;
hjk's avatar
hjk committed
308 309 310
        module.moduleName = item["name"].data();
        QString path = item["value"].data();
        int pos = path.indexOf("' from '");
hjk's avatar
hjk committed
311 312 313 314
        if (pos != -1) {
            path = path.mid(pos + 8);
            if (path.size() >= 2)
                path.chop(2);
hjk's avatar
hjk committed
315 316 317
        } else if (path.startsWith("<module '")
                && path.endsWith("' (built-in)>")) {
            path = "(builtin)";
hjk's avatar
hjk committed
318 319
        }
        module.modulePath = path;
320
        handler->updateModule(module);
hjk's avatar
hjk committed
321
    }
322
    handler->endUpdateAll();
hjk's avatar
hjk committed
323 324
}

hjk's avatar
hjk committed
325
void PdbEngine::requestModuleSymbols(const QString &moduleName)
hjk's avatar
hjk committed
326
{
hjk's avatar
hjk committed
327 328 329
    DebuggerCommand cmd("listSymbols");
    cmd.arg("module", moduleName);
    runCommand(cmd);
hjk's avatar
hjk committed
330 331
}

332 333
void PdbEngine::refreshState(const GdbMi &reportedState)
{
hjk's avatar
hjk committed
334
    QString newState = reportedState.data();
335 336 337 338 339 340 341 342
    if (newState == "stopped") {
        notifyInferiorSpontaneousStop();
        updateAll();
    } else if (newState == "inferiorexited") {
        notifyInferiorExited();
    }
}

343 344 345
void PdbEngine::refreshLocation(const GdbMi &reportedLocation)
{
    StackFrame frame;
hjk's avatar
hjk committed
346
    frame.file = reportedLocation["file"].data();
347
    frame.line = reportedLocation["line"].toInt();
348
    frame.usable = QFileInfo(frame.file).isReadable();
349
    if (state() == InferiorRunOk) {
hjk's avatar
hjk committed
350
        showMessage(QString("STOPPED AT: %1:%2").arg(frame.file).arg(frame.line));
351 352 353 354 355 356
        gotoLocation(frame);
        notifyInferiorSpontaneousStop();
        updateAll();
    }
}

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

369
bool PdbEngine::canHandleToolTip(const DebuggerToolTipContext &) const
hjk's avatar
hjk committed
370
{
371
    return state() == InferiorStopOk;
hjk's avatar
hjk committed
372 373
}

374
void PdbEngine::assignValueInDebugger(WatchItem *, const QString &expression, const QVariant &value)
375 376 377 378 379
{
    //DebuggerCommand cmd("assignValue");
    //cmd.arg("expression", expression);
    //cmd.arg("value", value.toString());
    //runCommand(cmd);
hjk's avatar
hjk committed
380
    postDirectCommand("global " + expression + ';' + expression + "=" + value.toString());
hjk's avatar
hjk committed
381 382 383
    updateLocals();
}

hjk's avatar
hjk committed
384
void PdbEngine::updateItem(const QString &iname)
hjk's avatar
hjk committed
385
{
386
    Q_UNUSED(iname);
hjk's avatar
hjk committed
387 388 389 390 391
    updateAll();
}

void PdbEngine::handlePdbError(QProcess::ProcessError error)
{
hjk's avatar
hjk committed
392
    showMessage("HANDLE PDB ERROR");
hjk's avatar
hjk committed
393 394 395 396 397 398 399 400
    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:
401
        //setState(EngineShutdownRequested, true);
402
        m_proc.kill();
hjk's avatar
hjk committed
403
        AsynchronousMessageBox::critical(tr("Pdb I/O Error"), errorMessage(error));
hjk's avatar
hjk committed
404 405 406 407 408 409 410 411 412
        break;
    }
}

QString PdbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
            return tr("The Pdb process failed to start. Either the "
413
                "invoked program \"%1\" is missing, or you may have insufficient "
hjk's avatar
hjk committed
414
                "permissions to invoke the program.")
hjk's avatar
hjk committed
415
                .arg(m_interpreter);
hjk's avatar
hjk committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
        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:
431
            return tr("An unknown error in the Pdb process occurred.") + QLatin1Char(' ');
hjk's avatar
hjk committed
432 433 434 435 436
    }
}

void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
{
hjk's avatar
hjk committed
437
    showMessage(QString("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
438
    notifyEngineSpontaneousShutdown();
hjk's avatar
hjk committed
439 440 441 442
}

void PdbEngine::readPdbStandardError()
{
hjk's avatar
hjk committed
443
    QString err = QString::fromUtf8(m_proc.readAllStandardError());
444
    //qWarning() << "Unexpected pdb stderr:" << err;
hjk's avatar
hjk committed
445
    showMessage("Unexpected pdb stderr: " + err);
446
    //handleOutput(err);
hjk's avatar
hjk committed
447 448 449 450
}

void PdbEngine::readPdbStandardOutput()
{
hjk's avatar
hjk committed
451
    QString out = QString::fromUtf8(m_proc.readAllStandardOutput());
452 453 454
    handleOutput(out);
}

hjk's avatar
hjk committed
455
void PdbEngine::handleOutput(const QString &data)
456 457 458
{
    m_inbuffer.append(data);
    while (true) {
459
        int pos = m_inbuffer.indexOf('\n');
460 461
        if (pos == -1)
            break;
hjk's avatar
hjk committed
462
        QString response = m_inbuffer.left(pos).trimmed();
463
        m_inbuffer = m_inbuffer.mid(pos + 1);
hjk's avatar
hjk committed
464
        handleOutput2(response);
465 466 467
    }
}

hjk's avatar
hjk committed
468
void PdbEngine::handleOutput2(const QString &data)
469
{
hjk's avatar
hjk committed
470
    foreach (QString line, data.split('\n')) {
471

hjk's avatar
hjk committed
472 473
        GdbMi item;
        item.fromString(line);
hjk's avatar
hjk committed
474

hjk's avatar
hjk committed
475
        showMessage(line, LogOutput);
476 477

        if (line.startsWith("stack={")) {
hjk's avatar
hjk committed
478
            refreshStack(item);
hjk's avatar
hjk committed
479
        } else if (line.startsWith("data={")) {
hjk's avatar
hjk committed
480
            refreshLocals(item);
hjk's avatar
hjk committed
481
        } else if (line.startsWith("modules=[")) {
hjk's avatar
hjk committed
482
            refreshModules(item);
hjk's avatar
hjk committed
483
        } else if (line.startsWith("symbols={")) {
hjk's avatar
hjk committed
484
            refreshSymbols(item);
485 486
        } else if (line.startsWith("location={")) {
            refreshLocation(item);
487 488
        } else if (line.startsWith("state=")) {
            refreshState(item);
hjk's avatar
hjk committed
489
        } else if (line.startsWith("Breakpoint")) {
hjk's avatar
hjk committed
490 491
            int pos1 = line.indexOf(" at ");
            QTC_ASSERT(pos1 != -1, continue);
hjk's avatar
hjk committed
492
            QString bpnr = line.mid(11, pos1 - 11);
hjk's avatar
hjk committed
493 494 495 496
            int pos2 = line.lastIndexOf(':');
            QTC_ASSERT(pos2 != -1, continue);
            BreakpointResponse br;
            br.id = BreakpointResponseId(bpnr);
hjk's avatar
hjk committed
497 498
            br.fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
            br.lineNumber = line.mid(pos2 + 1).toInt();
hjk's avatar
hjk committed
499 500 501 502 503 504
            Breakpoint bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
            if (bp.isValid()) {
                bp.setResponse(br);
                QTC_CHECK(!bp.needsChange());
                bp.notifyBreakpointInsertOk();
            }
505
        }
hjk's avatar
hjk committed
506 507
    }
}
hjk's avatar
hjk committed
508

509 510 511 512
void PdbEngine::refreshLocals(const GdbMi &vars)
{
    WatchHandler *handler = watchHandler();
    handler->resetValueCache();
513
    handler->insertItems(vars);
514
    handler->notifyUpdateFinished();
515 516 517 518 519 520 521 522 523 524

    DebuggerToolTipManager::updateEngine(this);
}

void PdbEngine::refreshStack(const GdbMi &stack)
{
    StackHandler *handler = stackHandler();
    StackFrames frames;
    foreach (const GdbMi &item, stack["frames"].children()) {
        StackFrame frame;
525
        frame.level = item["level"].data();
hjk's avatar
hjk committed
526 527 528
        frame.file = item["file"].data();
        frame.function = item["function"].data();
        frame.module = item["function"].data();
529
        frame.line = item["line"].toInt();
530
        frame.address = item["address"].toAddress();
531 532 533 534 535 536
        GdbMi usable = item["usable"];
        if (usable.isValid())
            frame.usable = usable.data().toInt();
        else
            frame.usable = QFileInfo(frame.file).isReadable();
        frames.append(frame);
hjk's avatar
hjk committed
537
    }
538 539 540 541 542 543 544 545
    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
546 547 548
}

void PdbEngine::updateAll()
549
{
550
    runCommand({"stackListFrames"});
551
    updateLocals();
552 553 554
}

void PdbEngine::updateLocals()
hjk's avatar
hjk committed
555
{
556 557 558
    DebuggerCommand cmd("updateData");
    cmd.arg("nativeMixed", isNativeMixedActive());
    watchHandler()->appendFormatRequests(&cmd);
hjk's avatar
hjk committed
559
    watchHandler()->appendWatchersAndTooltipRequests(&cmd);
hjk's avatar
hjk committed
560

561
    const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
562 563 564 565 566 567
    cmd.arg("passexceptions", alwaysVerbose);
    cmd.arg("fancy", boolSetting(UseDebuggingHelpers));

    //cmd.arg("resultvarname", m_resultVarName);
    //m_lastDebuggableCommand = cmd;
    //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
hjk's avatar
hjk committed
568
    cmd.arg("frame", stackHandler()->currentIndex());
569

570
    watchHandler()->notifyUpdateStarted();
571
    runCommand(cmd);
hjk's avatar
hjk committed
572 573
}

574
bool PdbEngine::hasCapability(unsigned cap) const
hjk's avatar
hjk committed
575
{
hjk's avatar
hjk committed
576 577 578
    return cap & (ReloadModuleCapability
              | BreakConditionCapability
              | ShowModuleSymbolsCapability);
hjk's avatar
hjk committed
579 580
}

581
DebuggerEngine *createPdbEngine()
hjk's avatar
hjk committed
582
{
583
    return new PdbEngine;
hjk's avatar
hjk committed
584 585 586 587
}

} // namespace Internal
} // namespace Debugger