asmimproved-dbgmits
Version:
Provides the ability to control GDB and LLDB programmatically via GDB/MI.
196 lines • 17.9 kB
JavaScript
// Copyright (c) 2015 Vadim Macagon
// MIT License, see LICENSE file for full terms.
;
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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