diff --git a/debugger/src/datasources.js b/debugger/src/datasources.js index 13843842c..f88230fcd 100644 --- a/debugger/src/datasources.js +++ b/debugger/src/datasources.js @@ -64,6 +64,7 @@ module.service('DataSource', function($q) { this.cache_ = { modules: {}, + moduleFunctionLists: {}, functions: {} }; }; @@ -104,10 +105,29 @@ module.service('DataSource', function($q) { }; DataSource.prototype.getFunctionList = function(moduleName) { - return this.issue({ + var d = $q.defer(); + var cached = this.cache_.moduleFunctionLists[moduleName]; + this.issue({ command: 'cpu.get_function_list', - module: moduleName - }); + 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; }; DataSource.prototype.getFunction = function(address) { diff --git a/src/alloy/runtime/module.cc b/src/alloy/runtime/module.cc index 4259eb829..cdc00bce1 100644 --- a/src/alloy/runtime/module.cc +++ b/src/alloy/runtime/module.cc @@ -97,6 +97,7 @@ SymbolInfo::Status Module::DeclareSymbol( break; } map_[address] = symbol_info; + list_.push_back(symbol_info); status = SymbolInfo::STATUS_NEW; } UnlockMutex(lock_); @@ -160,10 +161,25 @@ SymbolInfo::Status Module::DefineVariable(VariableInfo* symbol_info) { void Module::ForEachFunction(std::function callback) { LockMutex(lock_); - for (SymbolMap::iterator it = map_.begin(); - it != map_.end(); ++it) { - if (it->second->type() == SymbolInfo::TYPE_FUNCTION) { - FunctionInfo* info = (FunctionInfo*)it->second; + for (auto it = list_.begin(); it != list_.end(); ++it) { + SymbolInfo* symbol_info = *it; + if (symbol_info->type() == SymbolInfo::TYPE_FUNCTION) { + FunctionInfo* info = (FunctionInfo*)symbol_info; + callback(info); + } + } + UnlockMutex(lock_); +} + +void Module::ForEachFunction(size_t since, size_t& version, + std::function callback) { + LockMutex(lock_); + size_t count = list_.size(); + version = count; + for (size_t n = since; n < count; n++) { + SymbolInfo* symbol_info = list_[n]; + if (symbol_info->type() == SymbolInfo::TYPE_FUNCTION) { + FunctionInfo* info = (FunctionInfo*)symbol_info; callback(info); } } diff --git a/src/alloy/runtime/module.h b/src/alloy/runtime/module.h index bb86f0dc2..005e325a1 100644 --- a/src/alloy/runtime/module.h +++ b/src/alloy/runtime/module.h @@ -45,6 +45,8 @@ public: SymbolInfo::Status DefineVariable(VariableInfo* symbol_info); void ForEachFunction(std::function callback); + void ForEachFunction(size_t since, size_t& version, + std::function callback); int ReadMap(const char* file_name); @@ -62,6 +64,8 @@ private: Mutex* lock_; typedef std::tr1::unordered_map SymbolMap; SymbolMap map_; + typedef std::vector SymbolList; + SymbolList list_; }; diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 91bbc7c50..05ee02b43 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -225,6 +225,32 @@ void Processor::OnDebugClientDisconnected(uint32_t client_id) { runtime_->debugger()->ResumeAllThreads(true); } +json_t* json_object_set_string_new( + json_t* object, const char* key, const char* value) { + json_t* value_json = json_string(value); + json_object_set_new(object, key, value_json); + return value_json; +} + +json_t* json_object_set_string_format_new( + json_t* object, const char* key, const char* format, ...) { + char buffer[1024]; + va_list args; + va_start(args, format); + xevsnprintfa(buffer, XECOUNT(buffer), format, args); + va_end(args); + json_t* value_json = json_string(buffer); + json_object_set_new(object, key, value_json); + return value_json; +} + +json_t* json_object_set_integer_new( + json_t* object, const char* key, json_int_t value) { + json_t* value_json = json_integer(value); + json_object_set_new(object, key, value_json); + return value_json; +} + json_t* Processor::OnDebugRequest( uint32_t client_id, const char* command, json_t* request, bool& succeeded) { @@ -240,8 +266,7 @@ json_t* Processor::OnDebugRequest( for (auto it = modules.begin(); it != modules.end(); ++it) { XexModule* module = (XexModule*)(*it); json_t* module_json = json_object(); - json_t* module_name_json = json_string(module->name()); - json_object_set_new(module_json, "name", module_name_json); + json_object_set_string_new(module_json, "name", module->name()); json_array_append_new(list, module_json); } return list; @@ -270,8 +295,16 @@ json_t* Processor::OnDebugRequest( succeeded = false; return json_string("Module not found"); } + json_t* since_json = json_object_get(request, "since"); + if (since_json && !json_is_number(since_json)) { + succeeded = false; + return json_string("Version since is an invalid type"); + } + size_t since = since_json ? + (size_t)json_number_value(since_json) : 0; json_t* list = json_array(); - module->ForEachFunction([&](FunctionInfo* info) { + size_t version = 0; + module->ForEachFunction(since, version, [&](FunctionInfo* info) { json_t* fn_json = json_object(); const char* name = info->name(); char name_buffer[32]; @@ -280,15 +313,15 @@ json_t* Processor::OnDebugRequest( info->address()); name = name_buffer; } - json_t* name_json = json_string(name); - json_object_set_new(fn_json, "name", name_json); - json_t* address_json = json_integer(info->address()); - json_object_set_new(fn_json, "address", address_json); - json_t* link_status_json = json_integer(info->status()); - json_object_set_new(fn_json, "linkStatus", link_status_json); + json_object_set_string_new(fn_json, "name", name); + json_object_set_integer_new(fn_json, "address", info->address()); + json_object_set_integer_new(fn_json, "linkStatus", info->status()); json_array_append_new(list, fn_json); }); - return list; + json_t* result = json_object(); + json_object_set_integer_new(result, "version", version); + json_object_set_new(result, "list", list); + return result; } else if (xestrcmpa(command, "get_function") == 0) { json_t* address_json = json_object_get(request, "address"); if (!address_json || !json_is_number(address_json)) { @@ -397,32 +430,6 @@ json_t* Processor::OnDebugRequest( } } -json_t* json_object_set_string_new( - json_t* object, const char* key, const char* value) { - json_t* value_json = json_string(value); - json_object_set_new(object, key, value_json); - return value_json; -} - -json_t* json_object_set_string_format_new( - json_t* object, const char* key, const char* format, ...) { - char buffer[1024]; - va_list args; - va_start(args, format); - xevsnprintfa(buffer, XECOUNT(buffer), format, args); - va_end(args); - json_t* value_json = json_string(buffer); - json_object_set_new(object, key, value_json); - return value_json; -} - -json_t* json_object_set_integer_new( - json_t* object, const char* key, json_int_t value) { - json_t* value_json = json_integer(value); - json_object_set_new(object, key, value_json); - return value_json; -} - json_t* Processor::DumpModule(XexModule* module, bool& succeeded) { auto xex = module->xex(); auto header = xe_xex2_get_header(xex);