UNPKG

asmimproved-dbgmits

Version:

Provides the ability to control GDB and LLDB programmatically via GDB/MI.

196 lines 17.9 kB
// Copyright (c) 2015 Vadim Macagon // MIT License, see LICENSE file for full terms. "use strict"; require('source-map-support').install(); var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); var dbgmits = require('../lib/index'); var test_utils_1 = require('./test_utils'); chai.use(chaiAsPromised); // aliases var expect = chai.expect; // the directory in which Gruntfile.js resides is also Mocha's working directory, // so any relative paths will be relative to that directory var localTargetExe = './build/Debug/exec_tests_target'; test_utils_1.logSuite(describe("Debug Session", function () { describe("Program Execution", function () { var debugSession; var locationOfCallToPrintNextInt; before(function () { var lineResolver = test_utils_1.SourceLineResolver.loadSourceFileSync('./test/exec_tests_target.cpp'); var line = lineResolver.getCommentLineNumber('bp: main::printNextInt()'); locationOfCallToPrintNextInt = "exec_tests_target.cpp:" + line; }); test_utils_1.beforeEachTestWithLogger(function (logger) { debugSession = test_utils_1.startDebugSession(logger); return debugSession.setExecutableFile(localTargetExe); }); afterEach(function () { return debugSession.end(); }); it("starts the target process", function () { return debugSession.startInferior(); }); // FIXME: This test is skipped on GDB because this MI command is not supported even though // it was documented in the GDB/MI spec. it("aborts the target process @skipOnGDB", function () { var verifyTargetExited = function () { // Promises get executed when they're created, wrapping the promise creation in // a function makes it possible to delay execution return new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_TARGET_STOPPED, function (stopNotify) { // This event listener function gets invoked outside of the promise, // which means the promise doesn't trap any exception thrown here, // so we have to trap any exceptions manually and then hand them over // to the promise (if we don't an exception here will kill the test runner // instead of just failing this test). try { expect(stopNotify.reason).to.equal(dbgmits.TargetStopReason.ExitedNormally); resolve(); } catch (err) { reject(err); } }); }); }; // a breakpoint will be set to get to the desired starting point in the target process var onBreakpointAbortTarget = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_BREAKPOINT_HIT, function (breakNotify) { Promise.all([verifyTargetExited(), debugSession.abortInferior()]) .then(function () { resolve(); }, reject); }); }); // break at the start of main() return debugSession.addBreakpoint('main') .then(function () { return Promise.all([ onBreakpointAbortTarget, debugSession.startInferior() ]); }); }); it("steps into a source line", function () { // when the step is done check we're in printNextInt() var onStepFinishedCheckFrame = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_STEP_FINISHED, function (notification) { debugSession.getStackFrame() .then(function (info) { expect(info.func.indexOf('printNextInt')).to.equal(0); }) .then(resolve, reject); }); }); // a breakpoint will be set to get to the desired starting point in the target process var onBreakpointStepIntoLine = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_BREAKPOINT_HIT, function (notify) { // step into the printNextInt() call in main() resolve(debugSession.stepIntoLine()); }); }); // break on the line in main() that calls printNextInt() return debugSession.addBreakpoint(locationOfCallToPrintNextInt) .then(function () { return Promise.all([ onBreakpointStepIntoLine, onStepFinishedCheckFrame, debugSession.startInferior() ]); }); }); it("steps into an instruction", function () { // when the step is done check we're in printNextInt() var onStepFinishedCheckFrame = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_STEP_FINISHED, function (notification) { debugSession.getStackFrame() .then(function (info) { expect(info.func.indexOf('printNextInt')).to.equal(0); }) .then(resolve, reject); }); }); // a breakpoint will be set to get to the desired starting point in the target process var onBreakpointStepIntoInstruction = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_BREAKPOINT_HIT, function (notify) { // step into the printNextInt() call in main() resolve(debugSession.stepIntoInstruction()); }); }); // break on the line in main() that calls printNextInt() return debugSession.addBreakpoint(locationOfCallToPrintNextInt) .then(function () { return Promise.all([ onBreakpointStepIntoInstruction, onStepFinishedCheckFrame, debugSession.startInferior() ]); }); }); it("steps over a source line", function () { // when the step is done check we're still in main() and haven't stepped into printNextInt() var onStepFinishedCheckFrame = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_STEP_FINISHED, function (notification) { debugSession.getStackFrame() .then(function (info) { expect(info).to.have.property('func', 'main'); }) .then(resolve, reject); }); }); // a breakpoint will be set to get to the desired starting point in the target process var onBreakpointStepOverLine = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_BREAKPOINT_HIT, function (breakNotify) { // step over the printNextInt() call in main() resolve(debugSession.stepOverLine()); }); }); // break on the line in main() that calls printNextInt() return debugSession.addBreakpoint(locationOfCallToPrintNextInt) .then(function () { return Promise.all([ onBreakpointStepOverLine, onStepFinishedCheckFrame, debugSession.startInferior() ]); }); }); it("steps over an instruction", function () { // when the step is done check we're still in main() and haven't stepped into printNextInt() var onStepFinishedCheckFrame = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_STEP_FINISHED, function (notification) { debugSession.getStackFrame() .then(function (info) { expect(info).to.have.property('func', 'main'); }) .then(resolve, reject); }); }); // a breakpoint will be set to get to the desired starting point in the target process var onBreakpointStepOverInstruction = new Promise(function (resolve, reject) { debugSession.once(dbgmits.EVENT_BREAKPOINT_HIT, function (breakNotify) { // step over the printNextInt() call in main() resolve(debugSession.stepOverInstruction()); }); }); // break on the line in main() that calls printNextInt() return debugSession.addBreakpoint(locationOfCallToPrintNextInt) .then(function () { return Promise.all([ onBreakpointStepOverInstruction, onStepFinishedCheckFrame, debugSession.startInferior() ]); }); }); it("steps out of a function", function () { return test_utils_1.runToFuncAndStepOut(debugSession, 'printNextInt', function () { return debugSession.getStackFrame() .then(function (info) { // when the step is done check we're back in main() and not still in printNextInt() expect(info).to.have.property('func', 'main'); }); }); }); }); })); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhlY190ZXN0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3Rlc3QvZXhlY190ZXN0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxtQ0FBbUM7QUFDbkMsZ0RBQWdEOztBQUVoRCxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUV4QyxJQUFZLElBQUksV0FBTSxNQUFNLENBQUMsQ0FBQTtBQUM3QixJQUFPLGNBQWMsV0FBVyxrQkFBa0IsQ0FBQyxDQUFDO0FBRXBELElBQVksT0FBTyxXQUFNLGNBQWMsQ0FBQyxDQUFBO0FBQ3hDLDJCQUdPLGNBQWMsQ0FBQyxDQUFBO0FBRXRCLElBQUksQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7QUFFekIsVUFBVTtBQUNWLElBQUksTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7QUFHekIsaUZBQWlGO0FBQ2pGLDJEQUEyRDtBQUMzRCxJQUFJLGNBQWMsR0FBVyxpQ0FBaUMsQ0FBQztBQUUvRCxxQkFBRyxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUU7SUFDNUIsUUFBUSxDQUFDLG1CQUFtQixFQUFFO1FBQzVCLElBQUksWUFBMEIsQ0FBQztRQUMvQixJQUFJLDRCQUFvQyxDQUFDO1FBRXpDLE1BQU0sQ0FBQztZQUNMLElBQU0sWUFBWSxHQUFHLCtCQUFrQixDQUFDLGtCQUFrQixDQUFDLDhCQUE4QixDQUFDLENBQUM7WUFDM0YsSUFBTSxJQUFJLEdBQUcsWUFBWSxDQUFDLG9CQUFvQixDQUFDLDBCQUEwQixDQUFDLENBQUM7WUFDM0UsNEJBQTRCLEdBQUcsMkJBQXlCLElBQU0sQ0FBQztRQUNqRSxDQUFDLENBQUMsQ0FBQztRQUVILHFDQUF3QixDQUFDLFVBQUMsTUFBcUI7WUFDN0MsWUFBWSxHQUFHLDhCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pDLE1BQU0sQ0FBQyxZQUFZLENBQUMsaUJBQWlCLENBQUMsY0FBYyxDQUFDLENBQUM7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