Threads displayed.

This commit is contained in:
Ben Vanik 2013-12-25 17:31:53 -08:00
parent d368e0cb74
commit a1da55a006
19 changed files with 468 additions and 131 deletions

View file

@ -21,6 +21,7 @@ var module = angular.module('app', [
'xe.ui.code',
'xe.ui.code.functionView',
'xe.ui.code.moduleInfo',
'xe.ui.code.threadInfo',
'xe.ui.console',
'xe.ui.navbar'
]);

View file

@ -61,12 +61,6 @@ module.service('DataSource', function($q) {
this.delegate = delegate;
this.online = false;
this.status = 'disconnected';
this.cache_ = {
modules: {},
moduleFunctionLists: {},
functions: {}
};
};
inherits(DataSource, EventEmitter);
DataSource.prototype.open = function() {};
@ -86,69 +80,35 @@ module.service('DataSource', function($q) {
};
DataSource.prototype.getModule = function(moduleName) {
var d = $q.defer();
var cached = this.cache_.modules[moduleName];
if (cached) {
d.resolve(cached);
return d.promise;
}
this.issue({
return this.issue({
command: 'cpu.get_module',
module: moduleName
}).then((function(result) {
this.cache_.modules[moduleName] = result;
d.resolve(result);
}).bind(this), (function(e) {
d.reject(e);
}).bind(this));
return d.promise;
});
};
DataSource.prototype.getFunctionList = function(moduleName) {
var d = $q.defer();
var cached = this.cache_.moduleFunctionLists[moduleName];
this.issue({
DataSource.prototype.getFunctionList = function(moduleName, opt_since) {
return this.issue({
command: 'cpu.get_function_list',
module: moduleName,
since: cached ? cached.version : 0
}).then((function(result) {
if (cached) {
cached.version = result.version;
for (var n = 0; n < result.list.length; n++) {
cached.list.push(result.list[n]);
}
} else {
cached = this.cache_.moduleFunctionLists[moduleName] = {
version: result.version,
list: result.list
};
}
d.resolve(cached.list);
}).bind(this), (function(e) {
d.reject(e);
}).bind(this));
return d.promise;
since: opt_since || 0
});
};
DataSource.prototype.getFunction = function(address) {
var d = $q.defer();
var cached = this.cache_.functions[address];
if (cached) {
d.resolve(cached);
return d.promise;
}
this.issue({
return this.issue({
command: 'cpu.get_function',
address: address
}).then((function(result) {
this.cache_.functions[address] = result;
d.resolve(result);
}).bind(this), (function(e) {
d.reject(e);
}).bind(this));
return d.promise;
});
};
DataSource.prototype.getThreadStates = function() {
return this.issue({
command: 'cpu.get_thread_states'
});
};
// set registers/etc?
DataSource.prototype.addBreakpoint = function(breakpoint) {
return this.addBreakpoints([breakpoint]);
};

View file

@ -15,6 +15,154 @@ var module = angular.module('xe.session', []);
module.service('Session', function(
$rootScope, $q, $http, $state, log,
Breakpoint, FileDataSource, RemoteDataSource) {
var State = function(session) {
this.session = session;
this.clear();
};
State.prototype.clear = function() {
this.cache_ = {
moduleList: [],
modules: {},
moduleFunctionLists: {},
functions: {},
threadStates: {},
threadList: []
};
};
State.prototype.sync = function() {
var cache = this.cache_;
var dataSource = this.session.dataSource;
if (!dataSource) {
var d = $q.defer();
d.resolve();
return d.promise;
}
var ps = [];
// Update all modules/functions.
var modulesUpdated = $q.defer();
ps.push(modulesUpdated.promise);
dataSource.getModuleList().then((function(list) {
cache.moduleList = list;
// Update module information.
var moduleFetches = [];
list.forEach(function(module) {
if (cache.modules[module.name]) {
return;
}
var moduleFetch = $q.defer();
moduleFetches.push(moduleFetch.promise);
dataSource.getModule(module.name).
then(function(moduleInfo) {
cache.modules[module.name] = moduleInfo;
moduleFetch.resolve();
}, function(e) {
moduleFetch.reject(e);
});
});
// Update function lists for each module.
list.forEach(function(module) {
var cached = cache.moduleFunctionLists[module.name];
var functionListFetch = $q.defer();
moduleFetches.push(functionListFetch);
dataSource.getFunctionList(module.name, cached ? cached.version : 0).
then(function(result) {
if (cached) {
cached.version = result.version;
for (var n = 0; n < result.list.length; n++) {
cached.list.push(result.list[n]);
}
} else {
cached = cache.moduleFunctionLists[module.name] = {
version: result.version,
list: result.list
};
}
functionListFetch.resolve();
}, function(e) {
functionListFetch.reject(e);
});
});
$q.all(moduleFetches).then(function() {
modulesUpdated.resolve();
}, function(e) {
modulesUpdated.reject();
});
}).bind(this), function(e) {
modulesUpdated.reject(e);
});
// Update threads/thread states.
var threadsUpdated = $q.defer();
ps.push(threadsUpdated.promise);
dataSource.getThreadStates().then((function(states) {
cache.threadStates = states;
cache.threadList = [];
for (var threadId in states) {
cache.threadList.push(states[threadId]);
}
threadsUpdated.resolve();
}).bind(this), function(e) {
threadsUpdated.reject(e);
});
var d = $q.defer();
$q.all(ps).then((function() {
d.resolve();
}).bind(this), (function(e) {
d.reject(e);
}).bind(this));
return d.promise;
};
State.prototype.getModuleList = function() {
return this.cache_.moduleList;
};
State.prototype.getModule = function(moduleName) {
return this.cache_.modules[moduleName] || null;
};
State.prototype.getFunctionList = function(moduleName) {
var cached = this.cache_.moduleFunctionLists[moduleName];
return cached ? cached.list : [];
};
State.prototype.getFunction = function(address) {
return this.cache_.functions[address] || null;
};
State.prototype.fetchFunction = function(address) {
var cache = this.cache_;
var d = $q.defer();
var cached = cache.functions[address];
if (cached) {
d.resolve(cached);
return d.promise;
}
var dataSource = this.session.dataSource;
if (!dataSource) {
d.reject(new Error('Not online.'));
return d.promise;
}
dataSource.getFunction(address).then(function(result) {
cache.functions[address] = result;
d.resolve(result);
}, function(e) {
d.reject(e);
});
return d.promise;
}
Object.defineProperty(State.prototype, 'threadList', {
get: function() {
return this.cache_.threadList || [];
}
});
State.prototype.getThreadStates = function() {
return this.cache_.threadStates || {};
};
State.prototype.getThreadState = function(threadId) {
return this.cache_.threadStates[threadId] || null;
};
var Session = function(id, opt_dataSource) {
this.id = id;
@ -22,6 +170,9 @@ module.service('Session', function(
this.breakpointsById = {};
this.dataSource = opt_dataSource || null;
this.state = new State(this);
this.activeThread = null;
this.paused = false;
@ -144,6 +295,8 @@ module.service('Session', function(
d.resolve();
return d.promise;
}
this.state.clear();
this.activeThread = null;
this.dataSource = dataSource;
this.dataSource.on('online', function() {
@ -165,28 +318,31 @@ module.service('Session', function(
}
ps.push(this.dataSource.addBreakpoints(breakpointList));
// Fetch main module info.
// We need this for entry point info/etc.
var moduleInfoDeferred = $q.defer();
this.dataSource.getModuleList().then(function(moduleList) {
// Perform a full sync.
var syncDeferred = $q.defer();
ps.push(syncDeferred.promise);
this.state.sync().then((function() {
// Put a breakpoint at the entry point.
// TODO(benvanik): make an option?
var moduleList = this.state.getModuleList();
if (!moduleList.length) {
// Uh.
log.error('No modules loaded on startup!');
moduleInfoDeferred.reject(new Error('No modules found'));
log.error('No modules found!');
syncDeferred.reject(new Error('No modules found.'));
return;
}
moduleList.forEach(function(module) {
dataSource.getModule(module.name).then(function(moduleInfo) {
// Put a breakpoint at the entry point.
var entryPoint = moduleInfo.exeEntryPoint;
self.addTempBreakpoint(entryPoint, entryPoint);
moduleInfoDeferred.resolve();
});
});
}, function(e) {
moduleInfoDeferred.reject(e);
});
ps.push(moduleInfoDeferred.promise);
var moduleInfo = this.state.getModule(moduleList[0].name);
if (!moduleInfo) {
log.error('Main module not found!');
syncDeferred.reject(new Error('Main module not found.'));
return;
}
var entryPoint = moduleInfo.exeEntryPoint;
self.addTempBreakpoint(entryPoint, entryPoint);
syncDeferred.resolve();
}).bind(this), (function(e) {
syncDeferred.reject(e);
}).bind(this));
$q.all(ps).then((function() {
this.dataSource.makeReady().then(function() {
@ -258,16 +414,25 @@ module.service('Session', function(
// Now paused!
this.paused = true;
$rootScope.$emit('refresh');
this.state.sync().then((function() {
// Switch active thread.
var thread = this.state.getThreadState(threadId);
this.activeThread = thread;
if (breakpointId) {
var breakpoint = this.breakpointsById[breakpointId];
var thread = null; // TODO
if (!breakpoint) {
log.error('Breakpoint hit but not found');
if (!breakpointId) {
// Just a general pause.
log.info('Execution paused.');
return;
}
var breakpoint = this.breakpointsById[breakpointId];
if (!breakpoint) {
log.error('Breakpoint hit but not found.');
return;
}
// TODO(benvanik): stash current breakpoint/thread/etc.
log.info('Breakpoint hit at 0x' +
breakpoint.address.toString(16).toUpperCase() + '.');
@ -279,10 +444,9 @@ module.service('Session', function(
notify: true,
reloadOnSearch: false
});
} else {
// Just a general pause.
log.info('Execution paused.');
}
}).bind(this), (function(e) {
log.error('Unable to synchronize state,');
}).bind(this));
};
Session.prototype.continueExecution = function() {