File indexing completed on 2024-05-12 04:39:57
0001 /* 0002 SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com> 0003 SPDX-FileCopyrightText: 2013 Vlas Puhov <vlas.puhov@mail.ru> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "test_gdb.h" 0009 0010 #include "debugsession.h" 0011 #include "gdbframestackmodel.h" 0012 #include "mi/micommand.h" 0013 #include "mi/milexer.h" 0014 #include "mi/miparser.h" 0015 #include "tests/debuggers-tests-config.h" 0016 #include "tests/testhelper.h" 0017 0018 #include <execute/iexecuteplugin.h> 0019 #include <debugger/breakpoint/breakpoint.h> 0020 #include <debugger/breakpoint/breakpointmodel.h> 0021 #include <debugger/framestack/framestackmodel.h> 0022 #include <debugger/interfaces/ivariablecontroller.h> 0023 #include <debugger/variable/variablecollection.h> 0024 #include <interfaces/idebugcontroller.h> 0025 #include <interfaces/iplugincontroller.h> 0026 #include <tests/autotestshell.h> 0027 #include <tests/testcore.h> 0028 #include <shell/shellextension.h> 0029 0030 #include <KIO/Global> 0031 #include <KProcess> 0032 #include <KSharedConfig> 0033 #include <KShell> 0034 0035 #include <QApplication> 0036 #include <QDebug> 0037 #include <QDir> 0038 #include <QFileInfo> 0039 #include <QStandardPaths> 0040 #include <QSignalSpy> 0041 #include <QTest> 0042 #include <QTemporaryFile> 0043 0044 using KDevelop::AutoTestShell; 0045 using KDevMI::findExecutable; 0046 using KDevMI::findSourceFile; 0047 using KDevMI::findFile; 0048 0049 namespace KDevMI { namespace GDB { 0050 0051 void GdbTest::initTestCase() 0052 { 0053 #ifdef Q_OS_WIN 0054 QSKIP("apparently this test is killing processes, but is leaving kdeinit5, dbus-daemon and klauncher running, " 0055 "breaking the Windows CI builder"); 0056 #endif 0057 AutoTestShell::init(); 0058 KDevelop::TestCore::initialize(KDevelop::Core::NoUi); 0059 0060 m_iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute"))->extension<IExecutePlugin>(); 0061 Q_ASSERT(m_iface); 0062 } 0063 0064 void GdbTest::cleanupTestCase() 0065 { 0066 KDevelop::TestCore::shutdown(); 0067 } 0068 0069 void GdbTest::init() 0070 { 0071 //remove all breakpoints - so we can set our own in the test 0072 KConfigGroup breakpoints = KSharedConfig::openConfig()->group("breakpoints"); 0073 breakpoints.writeEntry("number", 0); 0074 breakpoints.sync(); 0075 0076 KDevelop::BreakpointModel* m = KDevelop::ICore::self()->debugController()->breakpointModel(); 0077 m->removeRows(0, m->rowCount()); 0078 0079 KDevelop::VariableCollection *vc = KDevelop::ICore::self()->debugController()->variableCollection(); 0080 for (int i=0; i < vc->watches()->childCount(); ++i) { 0081 delete vc->watches()->child(i); 0082 } 0083 vc->watches()->clear(); 0084 } 0085 0086 class TestFrameStackModel : public GdbFrameStackModel 0087 { 0088 Q_OBJECT 0089 0090 public: 0091 0092 explicit TestFrameStackModel(DebugSession* session) 0093 : GdbFrameStackModel(session), fetchFramesCalled(0), fetchThreadsCalled(0) {} 0094 0095 int fetchFramesCalled; 0096 int fetchThreadsCalled; 0097 void fetchFrames(int threadNumber, int from, int to) override 0098 { 0099 fetchFramesCalled++; 0100 GdbFrameStackModel::fetchFrames(threadNumber, from, to); 0101 } 0102 0103 void fetchThreads() override 0104 { 0105 fetchThreadsCalled++; 0106 GdbFrameStackModel::fetchThreads(); 0107 } 0108 }; 0109 0110 class TestDebugSession : public DebugSession 0111 { 0112 Q_OBJECT 0113 public: 0114 TestDebugSession() : DebugSession() 0115 { 0116 setSourceInitFile(false); 0117 setAutoDisableASLR(false); 0118 m_frameStackModel = new TestFrameStackModel(this); 0119 KDevelop::ICore::self()->debugController()->addSession(this); 0120 } 0121 0122 QUrl url() { return currentUrl(); } 0123 int line() { return currentLine(); } 0124 0125 TestFrameStackModel* frameStackModel() const override 0126 { 0127 return m_frameStackModel; 0128 } 0129 0130 private: 0131 TestFrameStackModel* m_frameStackModel; 0132 }; 0133 0134 static const QString debugeeFileName = findSourceFile(QStringLiteral("debugee.cpp")); 0135 0136 KDevelop::BreakpointModel* breakpoints() 0137 { 0138 return KDevelop::ICore::self()->debugController()->breakpointModel(); 0139 } 0140 0141 void GdbTest::testStdOut() 0142 { 0143 auto *session = new TestDebugSession; 0144 0145 QSignalSpy outputSpy(session, &TestDebugSession::inferiorStdoutLines); 0146 0147 TestLaunchConfiguration cfg; 0148 session->startDebugging(&cfg, m_iface); 0149 WAIT_FOR_STATE(session, KDevelop::IDebugSession::EndedState); 0150 0151 { 0152 QCOMPARE(outputSpy.count(), 1); 0153 QList<QVariant> arguments = outputSpy.takeFirst(); 0154 QCOMPARE(arguments.count(), 1); 0155 QCOMPARE(arguments.first().toStringList(), QStringList() << "Hello, world!" << "Hello"); 0156 } 0157 } 0158 0159 void GdbTest::testEnvironmentSet() 0160 { 0161 KDevMI::testEnvironmentSet(new TestDebugSession, QStringLiteral("GdbTestGroup"), m_iface); 0162 } 0163 0164 void GdbTest::testBreakpoint() 0165 { 0166 auto *session = new TestDebugSession; 0167 0168 TestLaunchConfiguration cfg; 0169 0170 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); 0171 QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState); 0172 0173 session->startDebugging(&cfg, m_iface); 0174 WAIT_FOR_STATE(session, DebugSession::PausedState); 0175 QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState); 0176 session->stepInto(); 0177 WAIT_FOR_STATE(session, DebugSession::PausedState); 0178 session->stepInto(); 0179 WAIT_FOR_STATE(session, DebugSession::PausedState); 0180 session->run(); 0181 WAIT_FOR_STATE(session, DebugSession::EndedState); 0182 0183 QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState); 0184 } 0185 0186 void GdbTest::testDisableBreakpoint() 0187 { 0188 //Description: We must stop only on the third breakpoint 0189 0190 int firstBreakLine=28; 0191 int secondBreakLine=23; 0192 int thirdBreakLine=24; 0193 int fourthBreakLine=31; 0194 0195 auto *session = new TestDebugSession; 0196 0197 TestLaunchConfiguration cfg; 0198 0199 KDevelop::Breakpoint *b; 0200 0201 b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), firstBreakLine); 0202 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 0203 0204 0205 //this is needed to emulate debug from GUI. If we are in edit mode, the debugSession doesn't exist. 0206 KDevelop::ICore::self()->debugController()->breakpointModel()->blockSignals(true); 0207 b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), secondBreakLine); 0208 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 0209 //all disabled breakpoints were added 0210 0211 KDevelop::Breakpoint * thirdBreak = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), thirdBreakLine); 0212 KDevelop::ICore::self()->debugController()->breakpointModel()->blockSignals(false); 0213 0214 0215 session->startDebugging(&cfg, m_iface); 0216 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0217 0218 QCOMPARE(session->currentLine(), thirdBreak->line()); 0219 0220 //disable existing breakpoint 0221 thirdBreak->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 0222 0223 //add another disabled breakpoint 0224 b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), fourthBreakLine); 0225 QTest::qWait(300); 0226 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 0227 0228 QTest::qWait(300); 0229 session->run(); 0230 WAIT_FOR_STATE(session, DebugSession::EndedState); 0231 } 0232 0233 void GdbTest::testChangeLocationBreakpoint() 0234 { 0235 auto *session = new TestDebugSession; 0236 0237 TestLaunchConfiguration cfg; 0238 0239 KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 27); 0240 0241 session->startDebugging(&cfg, m_iface); 0242 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0243 QCOMPARE(session->line(), 28); 0244 0245 QTest::qWait(100); 0246 b->setLine(29); 0247 QTest::qWait(100); 0248 session->run(); 0249 0250 QTest::qWait(100); 0251 WAIT_FOR_STATE(session, DebugSession::PausedState); 0252 QCOMPARE(session->line(), 29); 0253 QTest::qWait(500); 0254 breakpoints()->setData(breakpoints()->index(0, KDevelop::Breakpoint::LocationColumn), QString(debugeeFileName+":31")); 0255 QCOMPARE(b->line(), 30); 0256 QTest::qWait(100); 0257 QCOMPARE(b->line(), 30); 0258 session->run(); 0259 QTest::qWait(100); 0260 WAIT_FOR_STATE(session, DebugSession::PausedState); 0261 QCOMPARE(session->line(), 30); 0262 session->run(); 0263 0264 WAIT_FOR_STATE(session, DebugSession::EndedState); 0265 } 0266 0267 void GdbTest::testDeleteBreakpoint() 0268 { 0269 auto *session = new TestDebugSession; 0270 0271 TestLaunchConfiguration cfg; 0272 0273 QCOMPARE(breakpoints()->rowCount(), 0); 0274 //add breakpoint before startDebugging 0275 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21); 0276 QCOMPARE(breakpoints()->rowCount(), 1); 0277 QVERIFY(breakpoints()->removeRow(0)); 0278 QCOMPARE(breakpoints()->rowCount(), 0); 0279 0280 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22); 0281 0282 session->startDebugging(&cfg, m_iface); 0283 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0284 QVERIFY(breakpoints()->removeRow(0)); 0285 session->run(); 0286 0287 WAIT_FOR_STATE(session, DebugSession::EndedState); 0288 } 0289 0290 void GdbTest::testPendingBreakpoint() 0291 { 0292 auto *session = new TestDebugSession; 0293 TestLaunchConfiguration cfg; 0294 0295 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); 0296 0297 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile(QStringLiteral("debugeeqt.cpp"))), 10); 0298 QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState); 0299 0300 session->startDebugging(&cfg, m_iface); 0301 WAIT_FOR_STATE(session, DebugSession::PausedState); 0302 QCOMPARE(b->state(), KDevelop::Breakpoint::PendingState); 0303 session->run(); 0304 WAIT_FOR_STATE(session, DebugSession::EndedState); 0305 } 0306 0307 void GdbTest::testUpdateBreakpoint() 0308 { 0309 auto *session = new TestDebugSession; 0310 TestLaunchConfiguration cfg; 0311 0312 // breakpoint 1: real line 29: foo(); 0313 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); 0314 QCOMPARE(breakpoints()->rowCount(), 1); 0315 0316 session->startDebugging(&cfg, m_iface); 0317 0318 // breakpoint 2: real line 32: const char *x = "Hello"; 0319 //insert custom command as user might do it using GDB console 0320 session->addCommand(std::make_unique<MI::UserCommand>(MI::NonMI, "break " + debugeeFileName + ":32")); 0321 0322 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // stop at breakpoint 1, with custom command handled 0323 QCOMPARE(session->currentLine(), 28); 0324 0325 // check breakpoint 2 got picked up 0326 QCOMPARE(breakpoints()->rowCount(), 2); 0327 b = breakpoints()->breakpoint(1); 0328 QCOMPARE(b->url(), QUrl::fromLocalFile(debugeeFileName)); 0329 QCOMPARE(b->line(), 32); 0330 0331 session->run(); 0332 WAIT_FOR_STATE(session, DebugSession::PausedState); // stop at breakpoint 2 0333 QCOMPARE(session->currentLine(), 32); 0334 session->run(); 0335 WAIT_FOR_STATE(session, DebugSession::EndedState); 0336 } 0337 0338 void GdbTest::testIgnoreHitsBreakpoint() 0339 { 0340 auto *session = new TestDebugSession; 0341 TestLaunchConfiguration cfg; 0342 0343 KDevelop::Breakpoint * b1 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21); 0344 b1->setIgnoreHits(1); 0345 0346 KDevelop::Breakpoint * b2 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22); 0347 0348 session->startDebugging(&cfg, m_iface); 0349 0350 //WAIT_FOR_STATE(session, DebugSession::PausedState); 0351 WAIT_FOR(session, session->state() == DebugSession::PausedState && b2->hitCount() == 1); 0352 b2->setIgnoreHits(1); 0353 session->run(); 0354 //WAIT_FOR_STATE(session, DebugSession::PausedState); 0355 WAIT_FOR(session, session->state() == DebugSession::PausedState && b1->hitCount() == 1); 0356 session->run(); 0357 WAIT_FOR_STATE(session, DebugSession::EndedState); 0358 } 0359 0360 void GdbTest::testConditionBreakpoint() 0361 { 0362 auto *session = new TestDebugSession; 0363 TestLaunchConfiguration cfg; 0364 0365 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39); 0366 b->setCondition(QStringLiteral("x[0] == 'H'")); 0367 0368 b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 23); 0369 b->setCondition(QStringLiteral("i==2")); 0370 0371 b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 0372 0373 session->startDebugging(&cfg, m_iface); 0374 0375 WAIT_FOR(session, session->state() == DebugSession::PausedState && session->line() == 24); 0376 b->setCondition(QStringLiteral("i == 0")); 0377 QTest::qWait(100); 0378 session->run(); 0379 WAIT_FOR_STATE(session, DebugSession::PausedState); 0380 QCOMPARE(session->line(), 23); 0381 session->run(); 0382 WAIT_FOR_STATE(session, DebugSession::PausedState); 0383 QCOMPARE(session->line(), 39); 0384 session->run(); 0385 WAIT_FOR_STATE(session, DebugSession::EndedState); 0386 } 0387 0388 void GdbTest::testBreakOnWriteBreakpoint() 0389 { 0390 auto *session = new TestDebugSession; 0391 TestLaunchConfiguration cfg; 0392 0393 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 0394 0395 session->startDebugging(&cfg, m_iface); 0396 0397 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0398 QCOMPARE(session->line(), 24); 0399 0400 breakpoints()->addWatchpoint(QStringLiteral("i")); 0401 QTest::qWait(100); 0402 0403 session->run(); 0404 WAIT_FOR_STATE(session, DebugSession::PausedState); 0405 QCOMPARE(session->line(), 22); // line 23: ++i; int j = i; 0406 session->run(); 0407 WAIT_FOR_STATE(session, DebugSession::PausedState); 0408 QCOMPARE(session->line(), 24); 0409 session->run(); 0410 WAIT_FOR_STATE(session, DebugSession::EndedState); 0411 } 0412 0413 void GdbTest::testBreakOnWriteWithConditionBreakpoint() 0414 { 0415 auto *session = new TestDebugSession; 0416 TestLaunchConfiguration cfg; 0417 0418 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 0419 0420 session->startDebugging(&cfg, m_iface); 0421 0422 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0423 QCOMPARE(session->line(), 24); 0424 0425 KDevelop::Breakpoint *b = breakpoints()->addWatchpoint(QStringLiteral("i")); 0426 b->setCondition(QStringLiteral("i==2")); 0427 QTest::qWait(100); 0428 0429 session->run(); 0430 WAIT_FOR_STATE(session, DebugSession::PausedState); 0431 QCOMPARE(session->line(), 22); // line 23: ++i; int j = i; 0432 session->run(); 0433 WAIT_FOR_STATE(session, DebugSession::PausedState); 0434 QCOMPARE(session->line(), 24); 0435 session->run(); 0436 WAIT_FOR_STATE(session, DebugSession::EndedState); 0437 } 0438 0439 void GdbTest::testBreakOnReadBreakpoint() 0440 { 0441 /* 0442 test disabled because of gdb bug: http://sourceware.org/bugzilla/show_bug.cgi?id=10136 0443 0444 TestDebugSession *session = new TestDebugSession; 0445 TestLaunchConfiguration cfg; 0446 0447 KDevelop::Breakpoint *b = breakpoints()->addReadWatchpoint("foo::i"); 0448 0449 session->startDebugging(&cfg, m_iface); 0450 0451 WAIT_FOR_STATE(session, DebugSession::PausedState); 0452 QCOMPARE(session->line(), 23); 0453 session->run(); 0454 WAIT_FOR_STATE(session, DebugSession::EndedState); 0455 */ 0456 } 0457 0458 void GdbTest::testBreakOnReadBreakpoint2() 0459 { 0460 auto *session = new TestDebugSession; 0461 TestLaunchConfiguration cfg; 0462 0463 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 0464 0465 session->startDebugging(&cfg, m_iface); 0466 0467 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0468 QCOMPARE(session->line(), 24); 0469 0470 breakpoints()->addReadWatchpoint(QStringLiteral("i")); 0471 0472 session->run(); 0473 WAIT_FOR_STATE(session, DebugSession::PausedState); 0474 QCOMPARE(session->line(), 22); // ++i 0475 0476 session->run(); 0477 WAIT_FOR_STATE(session, DebugSession::PausedState); 0478 QCOMPARE(session->line(), 22); // int j = i 0479 0480 session->run(); 0481 WAIT_FOR_STATE(session, DebugSession::PausedState); 0482 if(session->line() == 22) { // some GDB versions break 3 times on this line 0483 session->run(); 0484 WAIT_FOR_STATE(session, DebugSession::PausedState); 0485 } 0486 QCOMPARE(session->line(), 24); 0487 0488 session->run(); 0489 WAIT_FOR_STATE(session, DebugSession::EndedState); 0490 } 0491 0492 void GdbTest::testBreakOnAccessBreakpoint() 0493 { 0494 auto *session = new TestDebugSession; 0495 TestLaunchConfiguration cfg; 0496 0497 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 0498 0499 session->startDebugging(&cfg, m_iface); 0500 0501 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0502 QCOMPARE(session->line(), 24); 0503 0504 breakpoints()->addAccessWatchpoint(QStringLiteral("i")); 0505 0506 session->run(); 0507 WAIT_FOR_STATE(session, DebugSession::PausedState); 0508 QCOMPARE(session->line(), 22); // line 23: ++i (read) 0509 0510 session->run(); 0511 WAIT_FOR_STATE(session, DebugSession::PausedState); 0512 QCOMPARE(session->line(), 22); // line 23: ++i (write) 0513 0514 session->run(); 0515 WAIT_FOR_STATE(session, DebugSession::PausedState); 0516 QCOMPARE(session->line(), 22); // line 23: int j = i (read) 0517 0518 session->run(); 0519 WAIT_FOR_STATE(session, DebugSession::PausedState); 0520 QCOMPARE(session->line(), 24); 0521 0522 session->run(); 0523 WAIT_FOR_STATE(session, DebugSession::EndedState); 0524 } 0525 0526 void GdbTest::testInsertBreakpointWhileRunning() 0527 { 0528 auto *session = new TestDebugSession; 0529 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow")); 0530 QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp")); 0531 0532 session->startDebugging(&cfg, m_iface); 0533 0534 WAIT_FOR_STATE(session, DebugSession::ActiveState); 0535 QTest::qWait(2000); 0536 qDebug() << "adding breakpoint"; 0537 KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 29); // ++i; 0538 QTest::qWait(500); 0539 WAIT_FOR_STATE(session, DebugSession::PausedState); 0540 QTest::qWait(500); 0541 QCOMPARE(session->line(), 29); // ++i; 0542 breakpoints()->removeBreakpoint(b); 0543 session->run(); 0544 WAIT_FOR_STATE(session, DebugSession::EndedState); 0545 } 0546 0547 void GdbTest::testInsertBreakpointWhileRunningMultiple() 0548 { 0549 auto *session = new TestDebugSession; 0550 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow")); 0551 QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp")); 0552 0553 session->startDebugging(&cfg, m_iface); 0554 0555 WAIT_FOR_STATE(session, DebugSession::ActiveState); 0556 QTest::qWait(2000); 0557 qDebug() << "adding breakpoint"; 0558 KDevelop::Breakpoint *b1 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 29); // static int i=0; 0559 KDevelop::Breakpoint *b2 = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 30); // ++i; 0560 QTest::qWait(500); 0561 WAIT_FOR_STATE(session, DebugSession::PausedState); 0562 QTest::qWait(500); 0563 QCOMPARE(session->line(), 29); // static int i=0; 0564 session->run(); 0565 WAIT_FOR_STATE(session, DebugSession::PausedState); 0566 QTest::qWait(500); 0567 QCOMPARE(session->line(), 30); // ++i; 0568 breakpoints()->removeBreakpoint(b1); 0569 breakpoints()->removeBreakpoint(b2); 0570 session->run(); 0571 WAIT_FOR_STATE(session, DebugSession::EndedState); 0572 } 0573 0574 void GdbTest::testInsertBreakpointFunctionName() 0575 { 0576 auto *session = new TestDebugSession; 0577 TestLaunchConfiguration cfg; 0578 0579 breakpoints()->addCodeBreakpoint(QStringLiteral("main")); 0580 0581 session->startDebugging(&cfg, m_iface); 0582 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0583 QCOMPARE(session->line(), 28); 0584 session->run(); 0585 WAIT_FOR_STATE(session, DebugSession::EndedState); 0586 } 0587 0588 void GdbTest::testManualBreakpoint() 0589 { 0590 auto *session = new TestDebugSession; 0591 TestLaunchConfiguration cfg; 0592 0593 breakpoints()->addCodeBreakpoint(QStringLiteral("main")); 0594 0595 session->startDebugging(&cfg, m_iface); 0596 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0597 QCOMPARE(session->line(), 28); 0598 0599 breakpoints()->removeRows(0, 1); 0600 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0601 QCOMPARE(breakpoints()->rowCount(), 0); 0602 0603 session->addCommand(MI::NonMI, QStringLiteral("break debugee.cpp:23")); 0604 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0605 QCOMPARE(breakpoints()->rowCount(), 1); 0606 0607 KDevelop::Breakpoint* b = breakpoints()->breakpoint(0); 0608 QCOMPARE(b->line(), 22); 0609 0610 session->addCommand(MI::NonMI, QStringLiteral("disable 2")); 0611 session->addCommand(MI::NonMI, QStringLiteral("condition 2 i == 1")); 0612 session->addCommand(MI::NonMI, QStringLiteral("ignore 2 1")); 0613 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0614 QCOMPARE(b->enabled(), false); 0615 QCOMPARE(b->condition(), QString("i == 1")); 0616 QCOMPARE(b->ignoreHits(), 1); 0617 0618 session->addCommand(MI::NonMI, QStringLiteral("delete 2")); 0619 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0620 QCOMPARE(breakpoints()->rowCount(), 0); 0621 0622 session->run(); 0623 WAIT_FOR_STATE(session, DebugSession::EndedState); 0624 } 0625 0626 void GdbTest::testShowStepInSource() 0627 { 0628 auto *session = new TestDebugSession; 0629 0630 QSignalSpy showStepInSourceSpy(session, &TestDebugSession::showStepInSource); 0631 0632 TestLaunchConfiguration cfg; 0633 0634 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29); 0635 session->startDebugging(&cfg, m_iface); 0636 WAIT_FOR_STATE(session, DebugSession::PausedState); 0637 session->stepInto(); 0638 WAIT_FOR_STATE(session, DebugSession::PausedState); 0639 session->stepInto(); 0640 WAIT_FOR_STATE(session, DebugSession::PausedState); 0641 session->run(); 0642 WAIT_FOR_STATE(session, DebugSession::EndedState); 0643 0644 { 0645 QCOMPARE(showStepInSourceSpy.count(), 3); 0646 QList<QVariant> arguments = showStepInSourceSpy.takeFirst(); 0647 QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName)); 0648 QCOMPARE(arguments.at(1).toInt(), 29); 0649 0650 arguments = showStepInSourceSpy.takeFirst(); 0651 QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName)); 0652 QCOMPARE(arguments.at(1).toInt(), 22); 0653 0654 arguments = showStepInSourceSpy.takeFirst(); 0655 QCOMPARE(arguments.first().toUrl(), QUrl::fromLocalFile(debugeeFileName)); 0656 QCOMPARE(arguments.at(1).toInt(), 23); 0657 } 0658 } 0659 0660 void GdbTest::testStack() 0661 { 0662 auto *session = new TestDebugSession; 0663 TestLaunchConfiguration cfg; 0664 0665 TestFrameStackModel *stackModel = session->frameStackModel(); 0666 0667 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21); 0668 QVERIFY(session->startDebugging(&cfg, m_iface)); 0669 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0670 0671 QModelIndex tIdx = stackModel->index(0,0); 0672 QCOMPARE(stackModel->rowCount(QModelIndex()), 1); 0673 QCOMPARE(stackModel->columnCount(QModelIndex()), 3); 0674 COMPARE_DATA(tIdx, "#1 at foo"); 0675 0676 QCOMPARE(stackModel->rowCount(tIdx), 2); 0677 QCOMPARE(stackModel->columnCount(tIdx), 3); 0678 COMPARE_DATA(stackModel->index(0, 0, tIdx), "0"); 0679 COMPARE_DATA(stackModel->index(0, 1, tIdx), "foo"); 0680 COMPARE_DATA(stackModel->index(0, 2, tIdx), debugeeFileName+":23"); 0681 COMPARE_DATA(stackModel->index(1, 0, tIdx), "1"); 0682 COMPARE_DATA(stackModel->index(1, 1, tIdx), "main"); 0683 COMPARE_DATA(stackModel->index(1, 2, tIdx), debugeeFileName+":30"); 0684 0685 0686 session->stepOut(); 0687 WAIT_FOR_STATE(session, DebugSession::PausedState); 0688 COMPARE_DATA(tIdx, "#1 at main"); 0689 QCOMPARE(stackModel->rowCount(tIdx), 1); 0690 COMPARE_DATA(stackModel->index(0, 0, tIdx), "0"); 0691 COMPARE_DATA(stackModel->index(0, 1, tIdx), "main"); 0692 // depending on the compiler and gdb version, we may either end up in 0693 // one line or the other 0694 const auto last = stackModel->index(0, 2, tIdx).data().toString(); 0695 if (last.endsWith(":30")) 0696 QCOMPARE(last, debugeeFileName + ":30"); 0697 else 0698 QCOMPARE(last, debugeeFileName + ":31"); 0699 0700 session->run(); 0701 WAIT_FOR_STATE(session, DebugSession::PausedState); 0702 session->run(); 0703 WAIT_FOR_STATE(session, DebugSession::EndedState); 0704 } 0705 0706 void GdbTest::testStackFetchMore() 0707 { 0708 auto *session = new TestDebugSession; 0709 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeerecursion")); 0710 QString fileName = findSourceFile(QStringLiteral("debugeerecursion.cpp")); 0711 0712 TestFrameStackModel *stackModel = session->frameStackModel(); 0713 0714 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 25); 0715 QVERIFY(session->startDebugging(&cfg, m_iface)); 0716 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0717 QCOMPARE(session->frameStackModel()->fetchFramesCalled, 1); 0718 0719 QModelIndex tIdx = stackModel->index(0,0); 0720 QCOMPARE(stackModel->rowCount(QModelIndex()), 1); 0721 QCOMPARE(stackModel->columnCount(QModelIndex()), 3); 0722 COMPARE_DATA(tIdx, "#1 at foo"); 0723 0724 QCOMPARE(stackModel->rowCount(tIdx), 21); 0725 COMPARE_DATA(stackModel->index(0, 0, tIdx), "0"); 0726 COMPARE_DATA(stackModel->index(0, 1, tIdx), "foo"); 0727 COMPARE_DATA(stackModel->index(0, 2, tIdx), fileName+":26"); 0728 COMPARE_DATA(stackModel->index(1, 0, tIdx), "1"); 0729 COMPARE_DATA(stackModel->index(1, 1, tIdx), "foo"); 0730 COMPARE_DATA(stackModel->index(1, 2, tIdx), fileName+":24"); 0731 COMPARE_DATA(stackModel->index(2, 0, tIdx), "2"); 0732 COMPARE_DATA(stackModel->index(2, 1, tIdx), "foo"); 0733 COMPARE_DATA(stackModel->index(2, 2, tIdx), fileName+":24"); 0734 COMPARE_DATA(stackModel->index(19, 0, tIdx), "19"); 0735 COMPARE_DATA(stackModel->index(20, 0, tIdx), "20"); 0736 0737 stackModel->fetchMoreFrames(); 0738 QTest::qWait(200); 0739 QCOMPARE(stackModel->fetchFramesCalled, 2); 0740 QCOMPARE(stackModel->rowCount(tIdx), 41); 0741 COMPARE_DATA(stackModel->index(20, 0, tIdx), "20"); 0742 COMPARE_DATA(stackModel->index(21, 0, tIdx), "21"); 0743 COMPARE_DATA(stackModel->index(22, 0, tIdx), "22"); 0744 COMPARE_DATA(stackModel->index(39, 0, tIdx), "39"); 0745 COMPARE_DATA(stackModel->index(40, 0, tIdx), "40"); 0746 0747 stackModel->fetchMoreFrames(); 0748 QTest::qWait(200); 0749 QCOMPARE(stackModel->fetchFramesCalled, 3); 0750 QCOMPARE(stackModel->rowCount(tIdx), 121); 0751 COMPARE_DATA(stackModel->index(40, 0, tIdx), "40"); 0752 COMPARE_DATA(stackModel->index(41, 0, tIdx), "41"); 0753 COMPARE_DATA(stackModel->index(42, 0, tIdx), "42"); 0754 COMPARE_DATA(stackModel->index(119, 0, tIdx), "119"); 0755 COMPARE_DATA(stackModel->index(120, 0, tIdx), "120"); 0756 0757 stackModel->fetchMoreFrames(); 0758 QTest::qWait(200); 0759 QCOMPARE(stackModel->fetchFramesCalled, 4); 0760 QCOMPARE(stackModel->rowCount(tIdx), 299); 0761 COMPARE_DATA(stackModel->index(120, 0, tIdx), "120"); 0762 COMPARE_DATA(stackModel->index(121, 0, tIdx), "121"); 0763 COMPARE_DATA(stackModel->index(122, 0, tIdx), "122"); 0764 COMPARE_DATA(stackModel->index(298, 0, tIdx), "298"); 0765 COMPARE_DATA(stackModel->index(298, 1, tIdx), "main"); 0766 COMPARE_DATA(stackModel->index(298, 2, tIdx), fileName+":30"); 0767 0768 stackModel->fetchMoreFrames(); //nothing to fetch, we are at the end 0769 QTest::qWait(200); 0770 QCOMPARE(stackModel->fetchFramesCalled, 4); 0771 QCOMPARE(stackModel->rowCount(tIdx), 299); 0772 0773 session->run(); 0774 WAIT_FOR_STATE(session, DebugSession::EndedState); 0775 } 0776 0777 void GdbTest::testStackDeactivateAndActive() 0778 { 0779 auto *session = new TestDebugSession; 0780 TestLaunchConfiguration cfg; 0781 0782 TestFrameStackModel *stackModel = session->frameStackModel(); 0783 0784 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 21); 0785 QVERIFY(session->startDebugging(&cfg, m_iface)); 0786 WAIT_FOR_STATE(session, DebugSession::PausedState); 0787 0788 QModelIndex tIdx = stackModel->index(0,0); 0789 0790 session->stepOut(); 0791 WAIT_FOR_STATE(session, DebugSession::PausedState); 0792 QTest::qWait(200); 0793 COMPARE_DATA(tIdx, "#1 at main"); 0794 QCOMPARE(stackModel->rowCount(tIdx), 1); 0795 COMPARE_DATA(stackModel->index(0, 0, tIdx), "0"); 0796 COMPARE_DATA(stackModel->index(0, 1, tIdx), "main"); 0797 // depending on the compiler and gdb version, we may either end up in 0798 // one line or the other 0799 const auto last = stackModel->index(0, 2, tIdx).data().toString(); 0800 if (last.endsWith(":30")) 0801 QCOMPARE(last, debugeeFileName + ":30"); 0802 else 0803 QCOMPARE(last, debugeeFileName + ":31"); 0804 0805 session->run(); 0806 WAIT_FOR_STATE(session, DebugSession::PausedState); 0807 session->run(); 0808 WAIT_FOR_STATE(session, DebugSession::EndedState); 0809 } 0810 0811 void GdbTest::testStackSwitchThread() 0812 { 0813 auto *session = new TestDebugSession; 0814 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeethreads")); 0815 QString fileName = findSourceFile(QStringLiteral("debugeethreads.cpp")); 0816 0817 TestFrameStackModel *stackModel = session->frameStackModel(); 0818 0819 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 42); // t3.start(); 0820 QVERIFY(session->startDebugging(&cfg, m_iface)); 0821 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 0822 0823 qDebug() << stackModel->rowCount(); 0824 QVERIFY(stackModel->rowCount() > 2); 0825 0826 QModelIndex tIdx = stackModel->index(0,0); 0827 COMPARE_DATA(tIdx, "#1 at main"); 0828 QCOMPARE(stackModel->rowCount(tIdx), 1); 0829 COMPARE_DATA(stackModel->index(0, 0, tIdx), "0"); 0830 COMPARE_DATA(stackModel->index(0, 1, tIdx), "main"); 0831 COMPARE_DATA(stackModel->index(0, 2, tIdx), fileName+":43"); // QThread::usleep(500000); 0832 0833 tIdx = stackModel->index(1,0); 0834 QVERIFY(stackModel->data(tIdx).toString().startsWith("#2 at ")); 0835 stackModel->setCurrentThread(2); 0836 QTRY_VERIFY(stackModel->rowCount(tIdx) > 3); 0837 0838 session->run(); 0839 WAIT_FOR_STATE(session, DebugSession::EndedState); 0840 } 0841 0842 void GdbTest::testAttach() 0843 { 0844 SKIP_IF_ATTACH_FORBIDDEN(); 0845 0846 QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp")); 0847 0848 KProcess debugeeProcess; 0849 debugeeProcess << QStringLiteral("nice") << findExecutable(QStringLiteral("debuggee_debugeeslow")).toLocalFile(); 0850 debugeeProcess.start(); 0851 QVERIFY(debugeeProcess.waitForStarted()); 0852 QTest::qWait(100); 0853 0854 auto *session = new TestDebugSession; 0855 session->attachToProcess(debugeeProcess.processId()); 0856 WAIT_FOR_STATE(session, DebugSession::PausedState); 0857 0858 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 39); // } after foo(); 0859 QTest::qWait(100); 0860 session->run(); 0861 QTest::qWait(2000); 0862 WAIT_FOR_STATE(session, DebugSession::PausedState); 0863 if (session->line() < 39 || session->line() < 40) { 0864 QCOMPARE(session->line(), 39); 0865 } 0866 0867 session->run(); 0868 WAIT_FOR_STATE(session, DebugSession::EndedState); 0869 } 0870 0871 void GdbTest::testManualAttach() 0872 { 0873 SKIP_IF_ATTACH_FORBIDDEN(); 0874 0875 KProcess debugeeProcess; 0876 debugeeProcess << QStringLiteral("nice") << findExecutable(QStringLiteral("debuggee_debugeeslow")).toLocalFile(); 0877 debugeeProcess.start(); 0878 QVERIFY(debugeeProcess.waitForStarted()); 0879 0880 auto *session = new TestDebugSession; 0881 0882 TestLaunchConfiguration cfg; 0883 cfg.config().writeEntry(Config::RemoteGdbRunEntry, 0884 QUrl::fromLocalFile(findFile(GDB_SRC_DIR, 0885 QStringLiteral("unittests/gdb_script_empty")))); 0886 QVERIFY(session->startDebugging(&cfg, m_iface)); 0887 0888 session->addCommand(MI::NonMI, QStringLiteral("attach %0").arg(debugeeProcess.processId())); 0889 WAIT_FOR_STATE(session, DebugSession::PausedState); 0890 0891 session->run(); 0892 QTest::qWait(2000); // give the slow inferior some extra time to run 0893 WAIT_FOR_STATE(session, DebugSession::EndedState); 0894 } 0895 0896 void GdbTest::testCoreFile() 0897 { 0898 QFileInfo f(QStringLiteral("core")); 0899 f.setCaching(false); // don't cache information 0900 if (f.exists()) { 0901 QVERIFY(QFile::remove(f.canonicalFilePath())); 0902 } 0903 0904 KProcess debugeeProcess; 0905 debugeeProcess.setOutputChannelMode(KProcess::MergedChannels); 0906 debugeeProcess << QStringLiteral("bash") << QStringLiteral("-c") 0907 << "ulimit -c unlimited; " 0908 + findExecutable(QStringLiteral("debuggee_crash")).toLocalFile(); 0909 debugeeProcess.start(); 0910 debugeeProcess.waitForFinished(); 0911 qDebug() << "Debuggee output:\n" << debugeeProcess.readAll(); 0912 0913 bool coreFileFound = f.exists(); 0914 if (!coreFileFound) { 0915 // Try to use coredumpctl 0916 auto coredumpctl = QStandardPaths::findExecutable(QStringLiteral("coredumpctl")); 0917 if (!coredumpctl.isEmpty()) { 0918 KProcess::execute(coredumpctl, {"-1", "-o", f.absoluteFilePath(), "dump", "debuggee_crash"}, 5000); 0919 // coredumpctl seems to create an empty file "core" even if no cores can be delivered 0920 // (like when run inside docker containers as on KDE CI or with kernel.core_pattern=|/dev/null) 0921 // so also check for size != 0 0922 coreFileFound = f.exists() && (f.size() > 0); 0923 } 0924 } 0925 if (!coreFileFound) 0926 QSKIP("no core dump found, check your system configuration (see /proc/sys/kernel/core_pattern)."); 0927 0928 auto *session = new TestDebugSession; 0929 session->examineCoreFile(findExecutable(QStringLiteral("debuggee_crash")), 0930 QUrl::fromLocalFile(f.canonicalFilePath())); 0931 0932 TestFrameStackModel *stackModel = session->frameStackModel(); 0933 0934 WAIT_FOR_STATE(session, DebugSession::StoppedState); 0935 0936 QModelIndex tIdx = stackModel->index(0,0); 0937 QCOMPARE(stackModel->rowCount(QModelIndex()), 1); 0938 QCOMPARE(stackModel->columnCount(QModelIndex()), 3); 0939 COMPARE_DATA(tIdx, "#1 at foo"); 0940 0941 session->stopDebugger(); 0942 WAIT_FOR_STATE(session, DebugSession::EndedState); 0943 } 0944 0945 0946 KDevelop::VariableCollection *variableCollection() 0947 { 0948 return KDevelop::ICore::self()->debugController()->variableCollection(); 0949 } 0950 0951 void GdbTest::testVariablesLocals() 0952 { 0953 auto *session = new TestDebugSession; 0954 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 0955 0956 TestLaunchConfiguration cfg; 0957 0958 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 22); 0959 QVERIFY(session->startDebugging(&cfg, m_iface)); 0960 WAIT_FOR_STATE(session, DebugSession::PausedState); 0961 QTest::qWait(1000); 0962 0963 QCOMPARE(variableCollection()->rowCount(), 2); 0964 QModelIndex i = variableCollection()->index(1, 0); 0965 COMPARE_DATA(i, "Locals"); 0966 QCOMPARE(variableCollection()->rowCount(i), 2); 0967 COMPARE_DATA(variableCollection()->index(0, 0, i), "i"); 0968 COMPARE_DATA(variableCollection()->index(0, 1, i), "0"); 0969 COMPARE_DATA(variableCollection()->index(1, 0, i), "j"); 0970 // COMPARE_DATA(variableCollection()->index(1, 1, i), "1"); // j is not initialized yet 0971 session->run(); 0972 QTest::qWait(1000); 0973 WAIT_FOR_STATE(session, DebugSession::PausedState); 0974 COMPARE_DATA(variableCollection()->index(0, 0, i), "i"); 0975 COMPARE_DATA(variableCollection()->index(0, 1, i), "1"); 0976 COMPARE_DATA(variableCollection()->index(1, 0, i), "j"); 0977 COMPARE_DATA(variableCollection()->index(1, 1, i), "1"); 0978 session->run(); 0979 WAIT_FOR_STATE(session, DebugSession::EndedState); 0980 } 0981 0982 void GdbTest::testVariablesLocalsStruct() 0983 { 0984 auto *session = new TestDebugSession; 0985 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 0986 0987 TestLaunchConfiguration cfg; 0988 0989 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39); 0990 QVERIFY(session->startDebugging(&cfg, m_iface)); 0991 WAIT_FOR_STATE(session, DebugSession::PausedState); 0992 QTest::qWait(1000); 0993 0994 QModelIndex i = variableCollection()->index(1, 0); 0995 QCOMPARE(variableCollection()->rowCount(i), 4); 0996 0997 int structIndex = 0; 0998 for(int j=0; j<3; ++j) { 0999 if (variableCollection()->index(j, 0, i).data().toString() == QLatin1String("ts")) { 1000 structIndex = j; 1001 } 1002 } 1003 1004 COMPARE_DATA(variableCollection()->index(structIndex, 0, i), "ts"); 1005 COMPARE_DATA(variableCollection()->index(structIndex, 1, i), "{...}"); 1006 QModelIndex ts = variableCollection()->index(structIndex, 0, i); 1007 COMPARE_DATA(variableCollection()->index(0, 0, ts), "..."); 1008 variableCollection()->expanded(ts); 1009 QTest::qWait(100); 1010 COMPARE_DATA(variableCollection()->index(0, 0, ts), "a"); 1011 COMPARE_DATA(variableCollection()->index(0, 1, ts), "0"); 1012 COMPARE_DATA(variableCollection()->index(1, 0, ts), "b"); 1013 COMPARE_DATA(variableCollection()->index(1, 1, ts), "1"); 1014 COMPARE_DATA(variableCollection()->index(2, 0, ts), "c"); 1015 COMPARE_DATA(variableCollection()->index(2, 1, ts), "2"); 1016 1017 session->stepInto(); 1018 WAIT_FOR_STATE(session, DebugSession::PausedState); 1019 QTest::qWait(1000); 1020 COMPARE_DATA(variableCollection()->index(structIndex, 0, i), "ts"); 1021 COMPARE_DATA(variableCollection()->index(structIndex, 1, i), "{...}"); 1022 COMPARE_DATA(variableCollection()->index(0, 1, ts), "1"); 1023 1024 session->run(); 1025 WAIT_FOR_STATE(session, DebugSession::EndedState); 1026 } 1027 1028 void GdbTest::testVariablesWatches() 1029 { 1030 auto *session = new TestDebugSession; 1031 KDevelop::ICore::self()->debugController()->variableCollection()->variableWidgetShown(); 1032 1033 TestLaunchConfiguration cfg; 1034 1035 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 39); 1036 QVERIFY(session->startDebugging(&cfg, m_iface)); 1037 WAIT_FOR_STATE(session, DebugSession::PausedState); 1038 1039 variableCollection()->watches()->add(QStringLiteral("ts")); 1040 QTest::qWait(300); 1041 1042 QModelIndex i = variableCollection()->index(0, 0); 1043 QCOMPARE(variableCollection()->rowCount(i), 1); 1044 COMPARE_DATA(variableCollection()->index(0, 0, i), "ts"); 1045 COMPARE_DATA(variableCollection()->index(0, 1, i), "{...}"); 1046 QModelIndex ts = variableCollection()->index(0, 0, i); 1047 COMPARE_DATA(variableCollection()->index(0, 0, ts), "..."); 1048 variableCollection()->expanded(ts); 1049 QTest::qWait(100); 1050 COMPARE_DATA(variableCollection()->index(0, 0, ts), "a"); 1051 COMPARE_DATA(variableCollection()->index(0, 1, ts), "0"); 1052 COMPARE_DATA(variableCollection()->index(1, 0, ts), "b"); 1053 COMPARE_DATA(variableCollection()->index(1, 1, ts), "1"); 1054 COMPARE_DATA(variableCollection()->index(2, 0, ts), "c"); 1055 COMPARE_DATA(variableCollection()->index(2, 1, ts), "2"); 1056 1057 session->stepInto(); 1058 WAIT_FOR_STATE(session, DebugSession::PausedState); 1059 QTest::qWait(100); 1060 COMPARE_DATA(variableCollection()->index(0, 0, i), "ts"); 1061 COMPARE_DATA(variableCollection()->index(0, 1, i), "{...}"); 1062 COMPARE_DATA(variableCollection()->index(0, 1, ts), "1"); 1063 1064 session->run(); 1065 WAIT_FOR_STATE(session, DebugSession::EndedState); 1066 } 1067 1068 void GdbTest::testVariablesWatchesQuotes() 1069 { 1070 auto *session = new TestDebugSession; 1071 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches); 1072 1073 TestLaunchConfiguration cfg; 1074 1075 // the unquoted string (the actual content): t\"t 1076 // quoted string (what we would write as a c string): "t\\\"t" 1077 // written in source file: R"("t\\\"t")" 1078 const QString testString(QStringLiteral("t\\\"t")); // the actual content 1079 const QString quotedTestString(QStringLiteral(R"("t\\\"t")")); 1080 1081 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38); 1082 QVERIFY(session->startDebugging(&cfg, m_iface)); 1083 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1084 1085 variableCollection()->watches()->add(quotedTestString); //just a constant string 1086 QTest::qWait(300); 1087 1088 QModelIndex i = variableCollection()->index(0, 0); 1089 QCOMPARE(variableCollection()->rowCount(i), 1); 1090 COMPARE_DATA(variableCollection()->index(0, 0, i), quotedTestString); 1091 COMPARE_DATA(variableCollection()->index(0, 1, i), "[" + QString::number(testString.length() + 1) + "]"); 1092 1093 QModelIndex testStr = variableCollection()->index(0, 0, i); 1094 COMPARE_DATA(variableCollection()->index(0, 0, testStr), "..."); 1095 variableCollection()->expanded(testStr); 1096 QTest::qWait(100); 1097 int len = testString.length(); 1098 for (int ind = 0; ind < len; ind++) 1099 { 1100 COMPARE_DATA(variableCollection()->index(ind, 0, testStr), QString::number(ind)); 1101 QChar c = testString.at(ind); 1102 QString value = QString::number(c.toLatin1()) + " '"; 1103 if (c == '\\') 1104 value += QLatin1String("\\\\"); 1105 else if (c == '\'') 1106 value += QLatin1String("\\'"); 1107 else 1108 value += c; 1109 value += QLatin1String("'"); 1110 COMPARE_DATA(variableCollection()->index(ind, 1, testStr), value); 1111 } 1112 COMPARE_DATA(variableCollection()->index(len, 0, testStr), QString::number(len)); 1113 COMPARE_DATA(variableCollection()->index(len, 1, testStr), "0 '\\000'"); 1114 1115 session->run(); 1116 WAIT_FOR_STATE(session, DebugSession::EndedState); 1117 } 1118 1119 void GdbTest::testVariablesWatchesTwoSessions() 1120 { 1121 auto *session = new TestDebugSession; 1122 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches); 1123 1124 TestLaunchConfiguration cfg; 1125 1126 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38); 1127 QVERIFY(session->startDebugging(&cfg, m_iface)); 1128 WAIT_FOR_STATE(session, DebugSession::PausedState); 1129 1130 variableCollection()->watches()->add(QStringLiteral("ts")); 1131 QTest::qWait(300); 1132 1133 QModelIndex ts = variableCollection()->index(0, 0, variableCollection()->index(0, 0)); 1134 variableCollection()->expanded(ts); 1135 QTest::qWait(100); 1136 session->run(); 1137 WAIT_FOR_STATE(session, DebugSession::EndedState); 1138 1139 //check if variable is marked as out-of-scope 1140 QCOMPARE(variableCollection()->watches()->childCount(), 1); 1141 auto* v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0)); 1142 QVERIFY(v); 1143 QVERIFY(!v->inScope()); 1144 QCOMPARE(v->childCount(), 3); 1145 v = qobject_cast<KDevelop::Variable*>(v->child(0)); 1146 QVERIFY(!v->inScope()); 1147 1148 //start a second debug session 1149 session = new TestDebugSession; 1150 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches); 1151 QVERIFY(session->startDebugging(&cfg, m_iface)); 1152 WAIT_FOR_STATE(session, DebugSession::PausedState); 1153 QTest::qWait(300); 1154 1155 QCOMPARE(variableCollection()->watches()->childCount(), 1); 1156 ts = variableCollection()->index(0, 0, variableCollection()->index(0, 0)); 1157 v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0)); 1158 QVERIFY(v); 1159 QVERIFY(v->inScope()); 1160 QCOMPARE(v->childCount(), 3); 1161 1162 v = qobject_cast<KDevelop::Variable*>(v->child(0)); 1163 QVERIFY(v->inScope()); 1164 QCOMPARE(v->data(1, Qt::DisplayRole).toString(), QString::number(0)); 1165 1166 session->run(); 1167 WAIT_FOR_STATE(session, DebugSession::EndedState); 1168 1169 //check if variable is marked as out-of-scope 1170 v = qobject_cast<KDevelop::Variable*>(variableCollection()->watches()->child(0)); 1171 QVERIFY(!v->inScope()); 1172 QVERIFY(!dynamic_cast<KDevelop::Variable*>(v->child(0))->inScope()); 1173 } 1174 1175 void GdbTest::testVariablesStopDebugger() 1176 { 1177 auto *session = new TestDebugSession; 1178 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1179 1180 TestLaunchConfiguration cfg; 1181 1182 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38); 1183 QVERIFY(session->startDebugging(&cfg, m_iface)); 1184 WAIT_FOR_STATE(session, DebugSession::PausedState); 1185 1186 session->stopDebugger(); 1187 QTest::qWait(300); 1188 } 1189 1190 1191 void GdbTest::testVariablesStartSecondSession() 1192 { 1193 QPointer<TestDebugSession> session = new TestDebugSession; 1194 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1195 1196 TestLaunchConfiguration cfg; 1197 1198 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38); 1199 QVERIFY(session->startDebugging(&cfg, m_iface)); 1200 WAIT_FOR_STATE(session, DebugSession::PausedState); 1201 1202 QPointer<TestDebugSession> session2 = new TestDebugSession; 1203 session2->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1204 1205 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38); 1206 QVERIFY(session2->startDebugging(&cfg, m_iface)); 1207 WAIT_FOR_STATE(session2, DebugSession::PausedState); 1208 1209 session2->run(); 1210 WAIT_FOR_STATE(session2, DebugSession::EndedState); 1211 } 1212 1213 void GdbTest::testVariablesSwitchFrame() 1214 { 1215 auto *session = new TestDebugSession; 1216 TestLaunchConfiguration cfg; 1217 1218 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1219 TestFrameStackModel *stackModel = session->frameStackModel(); 1220 1221 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 1222 QVERIFY(session->startDebugging(&cfg, m_iface)); 1223 WAIT_FOR_STATE(session, DebugSession::PausedState); 1224 QTest::qWait(500); 1225 1226 QModelIndex i = variableCollection()->index(1, 0); 1227 COMPARE_DATA(i, "Locals"); 1228 QCOMPARE(variableCollection()->rowCount(i), 2); 1229 COMPARE_DATA(variableCollection()->index(0, 0, i), "i"); 1230 COMPARE_DATA(variableCollection()->index(0, 1, i), "1"); 1231 COMPARE_DATA(variableCollection()->index(1, 0, i), "j"); 1232 1233 stackModel->setCurrentFrame(1); 1234 QTest::qWait(200); 1235 1236 i = variableCollection()->index(1, 0); 1237 QCOMPARE(variableCollection()->rowCount(i), 4); 1238 COMPARE_DATA(variableCollection()->index(2, 0, i), "argc"); 1239 COMPARE_DATA(variableCollection()->index(2, 1, i), "1"); 1240 COMPARE_DATA(variableCollection()->index(3, 0, i), "argv"); 1241 1242 breakpoints()->removeRow(0); 1243 session->run(); 1244 WAIT_FOR_STATE(session, DebugSession::EndedState); 1245 } 1246 1247 void GdbTest::testVariablesQuicklySwitchFrame() 1248 { 1249 auto *session = new TestDebugSession; 1250 TestLaunchConfiguration cfg; 1251 1252 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1253 TestFrameStackModel *stackModel = session->frameStackModel(); 1254 1255 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 1256 QVERIFY(session->startDebugging(&cfg, m_iface)); 1257 WAIT_FOR_STATE(session, DebugSession::PausedState); 1258 QTest::qWait(500); 1259 1260 QModelIndex i = variableCollection()->index(1, 0); 1261 COMPARE_DATA(i, "Locals"); 1262 QCOMPARE(variableCollection()->rowCount(i), 2); 1263 COMPARE_DATA(variableCollection()->index(0, 0, i), "i"); 1264 COMPARE_DATA(variableCollection()->index(0, 1, i), "1"); 1265 COMPARE_DATA(variableCollection()->index(1, 0, i), "j"); 1266 1267 stackModel->setCurrentFrame(1); 1268 QTest::qWait(300); 1269 stackModel->setCurrentFrame(0); 1270 QTest::qWait(1); 1271 stackModel->setCurrentFrame(1); 1272 QTest::qWait(1); 1273 stackModel->setCurrentFrame(0); 1274 QTest::qWait(1); 1275 stackModel->setCurrentFrame(1); 1276 QTest::qWait(500); 1277 1278 i = variableCollection()->index(1, 0); 1279 QCOMPARE(variableCollection()->rowCount(i), 4); 1280 QStringList locs; 1281 for (int j = 0; j < variableCollection()->rowCount(i); ++j) { 1282 locs << variableCollection()->index(j, 0, i).data().toString(); 1283 } 1284 QVERIFY(locs.contains("argc")); 1285 QVERIFY(locs.contains("argv")); 1286 QVERIFY(locs.contains("x")); 1287 1288 breakpoints()->removeRow(0); 1289 session->run(); 1290 WAIT_FOR_STATE(session, DebugSession::EndedState); 1291 } 1292 1293 1294 void GdbTest::testSegfaultDebugee() 1295 { 1296 auto *session = new TestDebugSession; 1297 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1298 TestLaunchConfiguration cfg(QStringLiteral("debuggee_crash")); 1299 QString fileName = findSourceFile(QStringLiteral("debugeecrash.cpp")); 1300 1301 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 23); 1302 1303 QVERIFY(session->startDebugging(&cfg, m_iface)); 1304 1305 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1306 QCOMPARE(session->line(), 23); 1307 session->run(); 1308 1309 WAIT_FOR_STATE(session, DebugSession::PausedState); 1310 QCOMPARE(session->line(), 24); 1311 1312 session->stopDebugger(); 1313 WAIT_FOR_STATE(session, DebugSession::EndedState); 1314 } 1315 1316 void GdbTest::testSwitchFrameGdbConsole() 1317 { 1318 auto *session = new TestDebugSession; 1319 1320 TestLaunchConfiguration cfg; 1321 1322 TestFrameStackModel *stackModel = session->frameStackModel(); 1323 1324 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 24); 1325 QVERIFY(session->startDebugging(&cfg, m_iface)); 1326 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1327 QCOMPARE(stackModel->currentFrame(), 0); 1328 stackModel->setCurrentFrame(1); 1329 QCOMPARE(stackModel->currentFrame(), 1); 1330 QTest::qWait(500); 1331 QCOMPARE(stackModel->currentFrame(), 1); 1332 1333 session->addUserCommand(QStringLiteral("print x")); 1334 QTest::qWait(500); 1335 //currentFrame must not reset to 0; Bug 222882 1336 QCOMPARE(stackModel->currentFrame(), 1); 1337 1338 } 1339 1340 //Bug 201771 1341 void GdbTest::testInsertAndRemoveBreakpointWhileRunning() 1342 { 1343 #ifdef Q_OS_FREEBSD 1344 QSKIP("apparently this test doesn't work on FreeBSD"); 1345 #endif 1346 1347 auto *session = new TestDebugSession; 1348 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeslow")); 1349 QString fileName = findSourceFile(QStringLiteral("debugeeslow.cpp")); 1350 1351 session->startDebugging(&cfg, m_iface); 1352 1353 WAIT_FOR_STATE(session, DebugSession::ActiveState); 1354 QTest::qWait(2000); 1355 qDebug() << "adding breakpoint"; 1356 KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 30); // ++i; 1357 breakpoints()->removeBreakpoint(b); 1358 WAIT_FOR_STATE(session, DebugSession::EndedState); 1359 } 1360 1361 //Bug 274390 1362 void GdbTest::testCommandOrderFastStepping() 1363 { 1364 auto *session = new TestDebugSession; 1365 1366 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeqt")); 1367 1368 breakpoints()->addCodeBreakpoint(QStringLiteral("main")); 1369 QVERIFY(session->startDebugging(&cfg, m_iface)); 1370 for(int i=0; i<20; i++) { 1371 session->stepInto(); 1372 } 1373 WAIT_FOR_STATE(session, DebugSession::PausedState); 1374 session->run(); 1375 WAIT_FOR_STATE(session, DebugSession::EndedState); 1376 } 1377 1378 void GdbTest::testPickupManuallyInsertedBreakpoint() 1379 { 1380 auto *session = new TestDebugSession; 1381 1382 TestLaunchConfiguration cfg; 1383 1384 breakpoints()->addCodeBreakpoint(QStringLiteral("main")); 1385 QVERIFY(session->startDebugging(&cfg, m_iface)); 1386 session->addCommand(MI::NonMI, QStringLiteral("break debugee.cpp:33")); 1387 session->stepInto(); 1388 WAIT_FOR_STATE(session, DebugSession::PausedState); 1389 QTest::qWait(1000); //wait for breakpoints update 1390 QCOMPARE(breakpoints()->breakpoints().count(), 2); 1391 QCOMPARE(breakpoints()->rowCount(), 2); 1392 KDevelop::Breakpoint *b = breakpoints()->breakpoint(1); 1393 QVERIFY(b); 1394 QCOMPARE(b->line(), 32); //we start with 0, gdb with 1 1395 QCOMPARE(b->url().fileName(), QString("debugee.cpp")); 1396 } 1397 1398 //Bug 270970 1399 void GdbTest::testPickupManuallyInsertedBreakpointOnlyOnce() 1400 { 1401 auto *session = new TestDebugSession; 1402 1403 //inject here, so it behaves similar like a command from .gdbinit 1404 QTemporaryFile configScript; 1405 configScript.open(); 1406 configScript.write(QStringLiteral("file %0\n").arg(findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile()).toLocal8Bit()); 1407 configScript.write("break debugee.cpp:32\n"); 1408 configScript.close(); 1409 1410 TestLaunchConfiguration cfg; 1411 KConfigGroup grp = cfg.config(); 1412 grp.writeEntry(Config::RemoteGdbConfigEntry, QUrl::fromLocalFile(configScript.fileName())); 1413 1414 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(QStringLiteral("debugee.cpp")), 31); 1415 QVERIFY(session->startDebugging(&cfg, m_iface)); 1416 1417 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1418 QCOMPARE(breakpoints()->breakpoints().count(), 1); 1419 1420 session->run(); 1421 WAIT_FOR_STATE(session, DebugSession::EndedState); 1422 } 1423 1424 void GdbTest::testPickupCatchThrowOnlyOnce() 1425 { 1426 QTemporaryFile configScript; 1427 configScript.open(); 1428 configScript.write("catch throw\n"); 1429 configScript.close(); 1430 1431 TestLaunchConfiguration cfg; 1432 KConfigGroup grp = cfg.config(); 1433 grp.writeEntry(Config::RemoteGdbConfigEntry, QUrl::fromLocalFile(configScript.fileName())); 1434 1435 1436 for (int i = 0; i < 2; ++i) { 1437 auto* session = new TestDebugSession; 1438 QVERIFY(session->startDebugging(&cfg, m_iface)); 1439 WAIT_FOR_STATE(session, DebugSession::EndedState); 1440 } 1441 1442 QTRY_COMPARE(breakpoints()->rowCount(), 1); //one from kdevelop, one from runScript 1443 } 1444 1445 void GdbTest::testRunGdbScript() 1446 { 1447 auto *session = new TestDebugSession; 1448 1449 QTemporaryFile runScript; 1450 runScript.open(); 1451 1452 runScript.write("file " + KShell::quoteArg(findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile()).toUtf8() + "\n"); 1453 runScript.write("break main\n"); 1454 runScript.write("run\n"); 1455 runScript.close(); 1456 1457 TestLaunchConfiguration cfg; 1458 KConfigGroup grp = cfg.config(); 1459 grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName())); 1460 1461 QVERIFY(session->startDebugging(&cfg, m_iface)); 1462 1463 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1464 1465 QCOMPARE(session->line(), 28); 1466 1467 session->run(); 1468 WAIT_FOR_STATE(session, DebugSession::EndedState); 1469 } 1470 1471 void GdbTest::testRemoteDebug() 1472 { 1473 const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver")); 1474 if (gdbserverExecutable.isEmpty()) { 1475 QSKIP("Skipping, gdbserver not available"); 1476 } 1477 1478 auto *session = new TestDebugSession; 1479 1480 QTemporaryFile shellScript(QDir::currentPath()+"/shellscript"); 1481 shellScript.open(); 1482 shellScript.write("gdbserver localhost:2345 " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n"); 1483 shellScript.close(); 1484 shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser); 1485 QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?) 1486 1487 QTemporaryFile runScript(QDir::currentPath()+"/runscript"); 1488 runScript.open(); 1489 runScript.write("file " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n"); 1490 runScript.write("target remote localhost:2345\n"); 1491 runScript.write("break debugee.cpp:30\n"); 1492 runScript.write("continue\n"); 1493 runScript.close(); 1494 1495 TestLaunchConfiguration cfg; 1496 KConfigGroup grp = cfg.config(); 1497 grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile((shellScript.fileName()+"-copy"))); 1498 grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName())); 1499 1500 QVERIFY(session->startDebugging(&cfg, m_iface)); 1501 1502 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1503 1504 QCOMPARE(session->line(), 29); 1505 1506 session->run(); 1507 WAIT_FOR_STATE(session, DebugSession::EndedState); 1508 1509 QFile::remove(shellScript.fileName()+"-copy"); 1510 } 1511 1512 void GdbTest::testRemoteDebugInsertBreakpoint() 1513 { 1514 const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver")); 1515 if (gdbserverExecutable.isEmpty()) { 1516 QSKIP("Skipping, gdbserver not available"); 1517 } 1518 1519 auto *session = new TestDebugSession; 1520 1521 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29); 1522 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 35); 1523 1524 QTemporaryFile shellScript(QDir::currentPath()+"/shellscript"); 1525 shellScript.open(); 1526 shellScript.write("gdbserver localhost:2345 " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + "\n"); 1527 shellScript.close(); 1528 shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser); 1529 QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?) 1530 1531 QTemporaryFile runScript(QDir::currentPath()+"/runscript"); 1532 runScript.open(); 1533 runScript.write("file " + findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toUtf8() + '\n'); 1534 runScript.write("target remote localhost:2345\n"); 1535 runScript.write("break debugee.cpp:30\n"); 1536 runScript.write("continue\n"); 1537 runScript.close(); 1538 1539 TestLaunchConfiguration cfg; 1540 KConfigGroup grp = cfg.config(); 1541 grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile(shellScript.fileName()+"-copy")); 1542 grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName())); 1543 1544 QVERIFY(session->startDebugging(&cfg, m_iface)); 1545 1546 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1547 1548 QCOMPARE(session->line(), 29); 1549 1550 QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript 1551 1552 session->run(); 1553 WAIT_FOR_STATE(session, DebugSession::PausedState); 1554 1555 QCOMPARE(session->line(), 36); 1556 1557 session->run(); 1558 WAIT_FOR_STATE(session, DebugSession::EndedState); 1559 1560 QFile::remove(shellScript.fileName()+"-copy"); 1561 } 1562 1563 1564 void GdbTest::testRemoteDebugInsertBreakpointPickupOnlyOnce() 1565 { 1566 const QString gdbserverExecutable = QStandardPaths::findExecutable(QStringLiteral("gdbserver")); 1567 if (gdbserverExecutable.isEmpty()) { 1568 QSKIP("Skipping, gdbserver not available"); 1569 } 1570 1571 auto *session = new TestDebugSession; 1572 1573 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 36); 1574 1575 QTemporaryFile shellScript(QDir::currentPath()+"/shellscript"); 1576 shellScript.open(); 1577 shellScript.write("gdbserver localhost:2345 "+findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toLatin1()+"\n"); 1578 shellScript.close(); 1579 shellScript.setPermissions(shellScript.permissions() | QFile::ExeUser); 1580 QFile::copy(shellScript.fileName(), shellScript.fileName()+"-copy"); //to avoid "Text file busy" on executing (why?) 1581 1582 QTemporaryFile runScript(QDir::currentPath()+"/runscript"); 1583 runScript.open(); 1584 runScript.write("file "+findExecutable(QStringLiteral("debuggee_debugee")).toLocalFile().toLatin1()+"\n"); 1585 runScript.write("target remote localhost:2345\n"); 1586 runScript.write("break debugee.cpp:31\n"); 1587 runScript.write("continue\n"); 1588 runScript.close(); 1589 1590 TestLaunchConfiguration cfg; 1591 KConfigGroup grp = cfg.config(); 1592 grp.writeEntry(Config::RemoteGdbShellEntry, QUrl::fromLocalFile((shellScript.fileName()+"-copy"))); 1593 grp.writeEntry(Config::RemoteGdbRunEntry, QUrl::fromLocalFile(runScript.fileName())); 1594 1595 QVERIFY(session->startDebugging(&cfg, m_iface)); 1596 1597 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1598 1599 QCOMPARE(session->line(), 30); 1600 1601 QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript 1602 1603 session->run(); 1604 WAIT_FOR_STATE(session, DebugSession::PausedState); 1605 1606 QCOMPARE(session->line(), 36); 1607 1608 session->run(); 1609 WAIT_FOR_STATE(session, DebugSession::EndedState); 1610 1611 //************************** second session 1612 session = new TestDebugSession; 1613 QVERIFY(session->startDebugging(&cfg, m_iface)); 1614 1615 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1616 1617 QCOMPARE(session->line(), 30); 1618 1619 QCOMPARE(breakpoints()->breakpoints().count(), 2); //one from kdevelop, one from runScript 1620 1621 session->run(); 1622 WAIT_FOR_STATE(session, DebugSession::PausedState); 1623 1624 QCOMPARE(session->line(), 36); 1625 1626 session->run(); 1627 WAIT_FOR_STATE(session, DebugSession::EndedState); 1628 1629 QFile::remove(shellScript.fileName()+"-copy"); 1630 } 1631 1632 void GdbTest::testBreakpointWithSpaceInPath() 1633 { 1634 auto *session = new TestDebugSession; 1635 1636 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeespace")); 1637 KConfigGroup grp = cfg.config(); 1638 QString fileName = findSourceFile(QStringLiteral("debugee space.cpp")); 1639 1640 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 20); 1641 QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState); 1642 1643 session->startDebugging(&cfg, m_iface); 1644 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1645 QCOMPARE(session->line(), 20); 1646 session->run(); 1647 WAIT_FOR_STATE(session, DebugSession::EndedState); 1648 } 1649 1650 void GdbTest::testBreakpointDisabledOnStart() 1651 { 1652 auto *session = new TestDebugSession; 1653 1654 TestLaunchConfiguration cfg; 1655 1656 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28) 1657 ->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 1658 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 29); 1659 KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 31); 1660 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 1661 1662 session->startDebugging(&cfg, m_iface); 1663 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1664 QCOMPARE(session->line(), 29); 1665 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Checked); 1666 session->run(); 1667 WAIT_FOR_STATE(session, DebugSession::PausedState); 1668 QCOMPARE(session->line(), 32); 1669 session->run(); 1670 WAIT_FOR_STATE(session, DebugSession::EndedState); 1671 } 1672 1673 void GdbTest::testCatchpoint() 1674 { 1675 auto *session = new TestDebugSession; 1676 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals); 1677 1678 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeeexception")); 1679 1680 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(findSourceFile(QStringLiteral("debugeeexception.cpp"))), 29); 1681 1682 session->startDebugging(&cfg, m_iface); 1683 WAIT_FOR_STATE(session, DebugSession::PausedState); 1684 QTest::qWait(1000); 1685 TestFrameStackModel* fsModel = session->frameStackModel(); 1686 QCOMPARE(fsModel->currentFrame(), 0); 1687 QCOMPARE(session->line(), 29); 1688 1689 session->addCommand(MI::NonMI, QStringLiteral("catch throw")); 1690 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1691 session->run(); 1692 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1693 QTest::qWait(1000); 1694 1695 const QVector<KDevelop::FrameStackModel::FrameItem> frames = fsModel->frames(fsModel->currentThread()); 1696 QVERIFY(frames.size() >= 2); 1697 // frame 0 is somewhere inside libstdc++ 1698 QCOMPARE(frames[1].file, QUrl::fromLocalFile(findSourceFile("debugeeexception.cpp"))); 1699 QCOMPARE(frames[1].line, 22); 1700 1701 QCOMPARE(breakpoints()->rowCount(),2); 1702 QVERIFY(!breakpoints()->breakpoint(0)->location().isEmpty()); 1703 QVERIFY(!breakpoints()->breakpoint(1)->location().isEmpty()); 1704 1705 session->run(); 1706 WAIT_FOR_STATE(session, DebugSession::EndedState); 1707 } 1708 1709 void GdbTest::testThreadAndFrameInfo() 1710 { 1711 // Check if --thread is added to user commands 1712 1713 auto *session = new TestDebugSession; 1714 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeethreads")); 1715 QString fileName = findSourceFile(QStringLiteral("debugeethreads.cpp")); 1716 1717 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(fileName), 38); 1718 QVERIFY(session->startDebugging(&cfg, m_iface)); 1719 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1720 1721 QSignalSpy outputSpy(session, &TestDebugSession::debuggerUserCommandOutput); 1722 1723 session->addCommand(std::make_unique<MI::UserCommand>(MI::ThreadInfo, QString())); 1724 session->addCommand(std::make_unique<MI::UserCommand>(MI::StackListLocals, QStringLiteral("0"))); 1725 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // wait for command finish 1726 1727 // outputs should be 1728 // 1. -thread-info 1729 // 2. ^done for thread-info 1730 // 3. -stack-list-locals 1731 // 4. ^done for -stack-list-locals 1732 QCOMPARE(outputSpy.count(), 4); 1733 QVERIFY(outputSpy.at(2).at(0).toString().contains(QLatin1String("--thread 1"))); 1734 1735 session->run(); 1736 WAIT_FOR_STATE(session, DebugSession::EndedState); 1737 } 1738 1739 void GdbTest::parseBug304730() 1740 { 1741 MI::FileSymbol file; 1742 file.contents = QByteArray("^done,bkpt={" 1743 "number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"<MULTIPLE>\",times=\"0\"," 1744 "original-location=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp:231\"}," 1745 "{number=\"1.1\",enabled=\"y\",addr=\"0x081d84aa\"," 1746 "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >" 1747 "::Propagation<ForwardPropagationNeighbors>(ForwardPropagationNeighbors)\"," 1748 "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\"," 1749 "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"}," 1750 "{number=\"1.2\",enabled=\"y\",addr=\"0x081d8ae2\"," 1751 "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >" 1752 "::Propagation<BackwardPropagationNeighbors>(BackwardPropagationNeighbors)\"," 1753 "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\"," 1754 "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"}," 1755 "{number=\"1.3\",enabled=\"y\",addr=\"0x081d911a\"," 1756 "func=\"PatchMatch<itk::Image<itk::CovariantVector<unsigned char, 3u>, 2u> >" 1757 "::Propagation<AllowedPropagationNeighbors>(AllowedPropagationNeighbors)\"," 1758 "file=\"/media/portable/Projects/BDSInpainting/Drivers/../PatchMatch/PatchMatch.hpp\"," 1759 "fullname=\"/media/portable/Projects/BDSInpainting/PatchMatch/PatchMatch.hpp\",line=\"231\"}"); 1760 1761 MI::MIParser parser; 1762 1763 std::unique_ptr<MI::Record> record(parser.parse(&file)); 1764 QVERIFY(record.get() != nullptr); 1765 } 1766 1767 void GdbTest::testMultipleLocationsBreakpoint() 1768 { 1769 auto *session = new TestDebugSession; 1770 1771 TestLaunchConfiguration cfg(QStringLiteral("debuggee_debugeemultilocbreakpoint")); 1772 1773 breakpoints()->addCodeBreakpoint(QStringLiteral("aPlusB")); 1774 1775 //TODO check if the additional location breakpoint is added 1776 1777 session->startDebugging(&cfg, m_iface); 1778 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1779 QCOMPARE(session->line(), 19); 1780 1781 session->run(); 1782 WAIT_FOR_STATE(session, DebugSession::PausedState); 1783 QCOMPARE(session->line(), 23); 1784 1785 session->run(); 1786 WAIT_FOR_STATE(session, DebugSession::EndedState); 1787 } 1788 1789 void GdbTest::testBug301287() 1790 { 1791 auto *session = new TestDebugSession; 1792 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches); 1793 1794 TestLaunchConfiguration cfg; 1795 1796 breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); 1797 1798 session->startDebugging(&cfg, m_iface); 1799 WAIT_FOR_STATE(session, DebugSession::PausedState); 1800 1801 variableCollection()->watches()->add(QStringLiteral("argc")); 1802 QTest::qWait(300); 1803 1804 QModelIndex i = variableCollection()->index(0, 0); 1805 QCOMPARE(variableCollection()->rowCount(i), 1); 1806 COMPARE_DATA(variableCollection()->index(0, 0, i), "argc"); 1807 COMPARE_DATA(variableCollection()->index(0, 1, i), "1"); 1808 1809 session->run(); 1810 WAIT_FOR_STATE(session, DebugSession::EndedState); 1811 1812 //start second debug session (same cfg) 1813 session = new TestDebugSession; 1814 session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateWatches); 1815 1816 session->startDebugging(&cfg, m_iface); 1817 WAIT_FOR_STATE(session, DebugSession::PausedState); 1818 1819 QTest::qWait(300); 1820 1821 i = variableCollection()->index(0, 0); 1822 QCOMPARE(variableCollection()->rowCount(i), 1); 1823 COMPARE_DATA(variableCollection()->index(0, 0, i), "argc"); 1824 COMPARE_DATA(variableCollection()->index(0, 1, i), "1"); 1825 1826 session->run(); 1827 WAIT_FOR_STATE(session, DebugSession::EndedState); 1828 } 1829 1830 void GdbTest::testMultipleBreakpoint() 1831 { 1832 auto *session = new TestDebugSession; 1833 1834 //there'll be about 3-4 breakpoints, but we treat it like one. 1835 TestLaunchConfiguration c(QStringLiteral("debuggee_debugeemultiplebreakpoint")); 1836 KDevelop::Breakpoint *b = breakpoints()->addCodeBreakpoint(QStringLiteral("debugeemultiplebreakpoint.cpp:52")); 1837 session->startDebugging(&c, m_iface); 1838 WAIT_FOR_STATE(session, DebugSession::PausedState); 1839 QCOMPARE(breakpoints()->breakpoints().count(), 1); 1840 1841 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 1842 session->run(); 1843 WAIT_FOR_STATE(session, DebugSession::EndedState); 1844 } 1845 1846 void GdbTest::testRegularExpressionBreakpoint() 1847 { 1848 auto *session = new TestDebugSession; 1849 1850 TestLaunchConfiguration c(QStringLiteral("debuggee_debugeemultilocbreakpoint")); 1851 breakpoints()->addCodeBreakpoint(QStringLiteral("main")); 1852 session->startDebugging(&c, m_iface); 1853 WAIT_FOR_STATE(session, DebugSession::PausedState); 1854 session->addCommand(MI::NonMI, QStringLiteral("rbreak .*aPl.*B")); 1855 QTest::qWait(100); 1856 session->run(); 1857 WAIT_FOR_STATE(session, DebugSession::PausedState); 1858 QCOMPARE(breakpoints()->breakpoints().count(), 3); 1859 1860 session->addCommand(MI::BreakDelete, QString()); 1861 session->run(); 1862 WAIT_FOR_STATE(session, DebugSession::EndedState); 1863 } 1864 1865 void GdbTest::testChangeBreakpointWhileRunning() 1866 { 1867 #ifdef Q_OS_FREEBSD 1868 QSKIP("apparently this test doesn't work on FreeBSD"); 1869 #endif 1870 1871 auto *session = new TestDebugSession; 1872 1873 TestLaunchConfiguration c(QStringLiteral("debuggee_debugeeslow")); 1874 KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QStringLiteral("debugeeslow.cpp:30")); 1875 session->startDebugging(&c, m_iface); 1876 1877 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1878 QVERIFY(session->currentLine() >= 29 && session->currentLine() <= 31 ); 1879 session->run(); 1880 WAIT_FOR_STATE(session, DebugSession::ActiveState); 1881 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 1882 //to make one loop 1883 QTest::qWait(2000); 1884 WAIT_FOR_STATE(session, DebugSession::ActiveState); 1885 1886 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Checked); 1887 QTest::qWait(100); 1888 WAIT_FOR_STATE(session, DebugSession::PausedState); 1889 b->setData(KDevelop::Breakpoint::EnableColumn, Qt::Unchecked); 1890 session->run(); 1891 QTest::qWait(100); 1892 WAIT_FOR_STATE(session, DebugSession::EndedState); 1893 } 1894 1895 void GdbTest::testDebugInExternalTerminal() 1896 { 1897 TestLaunchConfiguration cfg; 1898 1899 const QStringList consoles { "konsole", "xterm", "xfce4-terminal", "gnome-terminal" }; 1900 for (const QString& console : consoles) { 1901 1902 TestDebugSession* session = nullptr; 1903 if (QStandardPaths::findExecutable(console).isEmpty()) { 1904 continue; 1905 } 1906 1907 session = new TestDebugSession(); 1908 1909 cfg.config().writeEntry(IExecutePlugin::useTerminalEntry, true); 1910 cfg.config().writeEntry(IExecutePlugin::terminalEntry, console); 1911 1912 KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); 1913 1914 session->startDebugging(&cfg, m_iface); 1915 WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); 1916 QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState); 1917 session->stepInto(); 1918 WAIT_FOR_STATE(session, DebugSession::PausedState); 1919 session->run(); 1920 WAIT_FOR_STATE(session, DebugSession::EndedState); 1921 } 1922 } 1923 1924 // see: https://bugs.kde.org/show_bug.cgi?id=339231 1925 void GdbTest::testPathWithSpace() 1926 { 1927 auto* session = new TestDebugSession; 1928 1929 auto debugee = findExecutable(QStringLiteral("path with space/debuggee_spacedebugee")); 1930 TestLaunchConfiguration c(debugee, KIO::upUrl(debugee)); 1931 KDevelop::Breakpoint* b = breakpoints()->addCodeBreakpoint(QStringLiteral("spacedebugee.cpp:30")); 1932 QCOMPARE(b->state(), KDevelop::Breakpoint::NotStartedState); 1933 session->startDebugging(&c, m_iface); 1934 1935 WAIT_FOR_STATE(session, DebugSession::PausedState); 1936 QCOMPARE(b->state(), KDevelop::Breakpoint::CleanState); 1937 session->run(); 1938 WAIT_FOR_STATE(session, DebugSession::EndedState); 1939 } 1940 1941 } // end of namespace GDB 1942 } // end of namespace KDevMI 1943 1944 QTEST_MAIN(KDevMI::GDB::GdbTest) 1945 1946 1947 #include "test_gdb.moc" 1948 #include "moc_test_gdb.cpp" 1949