diff --git a/debugger/assets/ui/code/code-tab.js b/debugger/assets/ui/code/code-tab.js index 1dcbd7735..5e746e5be 100644 --- a/debugger/assets/ui/code/code-tab.js +++ b/debugger/assets/ui/code/code-tab.js @@ -21,7 +21,11 @@ module.controller('CodeTabController', function( $scope.selectedModule = null; $scope.functionList = []; - $rootScope.$on('refresh', function() { + function refresh() { + if (!app.session || !app.session.dataSource) { + $scope.moduleList = []; + return; + } var dataSource = app.session.dataSource; dataSource.getModuleList().then(function(list) { @@ -38,7 +42,8 @@ module.controller('CodeTabController', function( }); console.log('refresh'); - }); + }; + $rootScope.$on('refresh', refresh); $scope.selectModule = function(module) { var moduleChange = module != $scope.selectedModule; @@ -55,4 +60,8 @@ module.controller('CodeTabController', function( log.error('Unable to fetch function list'); }); }; + + if (app.session.dataSource) { + refresh(); + } }); diff --git a/debugger/assets/ui/code/function-view.html b/debugger/assets/ui/code/function-view.html index 884fcf884..39bd3d1a0 100644 --- a/debugger/assets/ui/code/function-view.html +++ b/debugger/assets/ui/code/function-view.html @@ -7,9 +7,12 @@
-
diff --git a/debugger/assets/ui/code/function-view.js b/debugger/assets/ui/code/function-view.js index c9d46163d..865cc1cc6 100644 --- a/debugger/assets/ui/code/function-view.js +++ b/debugger/assets/ui/code/function-view.js @@ -17,17 +17,47 @@ var module = angular.module('xe.ui.code.functionView', [ module.controller('FunctionViewController', function( $rootScope, $scope, app, log) { - $scope.codeType = 'ppc'; + $scope.codeType = 'source'; function refresh() { + if (!app.session || !app.session.dataSource) { + $scope.fn = null; + return; + } var dataSource = app.session.dataSource; dataSource.getFunction($scope.functionAddress).then(function(fn) { $scope.fn = fn; + updateCode(); }, function(e) { log.error('Unable to fetch function'); }); }; $rootScope.$on('refresh', refresh); $scope.$watch('functionAddress', refresh); + + var textArea = document.querySelector('.debugger-fnview-textarea'); + $scope.codeMirror = CodeMirror.fromTextArea(textArea, { + mode: 'javascript', + theme: 'default', + indentUnit: 2, + tabSize: 2, + lineNumbers: true, + firstLineNumber: 0, + lineNumberFormatter: function(line) { + return String(line); + }, + gutters: [], + readOnly: true + }); + + function updateCode() { + var codeType = $scope.codeType; + var value = ''; + if ($scope.fn) { + value = $scope.fn.disasm[codeType]; + } + $scope.codeMirror.setValue(value || ''); + }; + $scope.$watch('codeType', updateCode); }); diff --git a/debugger/assets/ui/navbar.html b/debugger/assets/ui/navbar.html index 3539d379a..c73759112 100644 --- a/debugger/assets/ui/navbar.html +++ b/debugger/assets/ui/navbar.html @@ -16,9 +16,9 @@ - diff --git a/debugger/debugger.js b/debugger/debugger.js index 5056af365..e8f39d267 100644 --- a/debugger/debugger.js +++ b/debugger/debugger.js @@ -6,22 +6,3 @@ * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ - -/* -var myTextArea = document.querySelector('.debugger-fnview-textarea'); -var myCodeMirror = CodeMirror.fromTextArea(myTextArea, { - mode: 'javascript', - theme: 'default', - indentUnit: 2, - tabSize: 2, - - lineNumbers: true, - firstLineNumber: 0, - lineNumberFormatter: function(line) { - return String('0x00000000' + line); - }, - gutters: [], - - //readOnly: true, -}); -*/ diff --git a/debugger/index.html b/debugger/index.html index 41b7f67c6..593892a87 100644 --- a/debugger/index.html +++ b/debugger/index.html @@ -7,7 +7,7 @@ - + @@ -19,7 +19,7 @@
- + diff --git a/debugger/src/app.js b/debugger/src/app.js index d53c03cd0..a29e80f5a 100644 --- a/debugger/src/app.js +++ b/debugger/src/app.js @@ -41,6 +41,7 @@ module.service('app', function( this.close(); this.session = session; + $rootScope.$emit('refresh'); }; App.prototype.close = function() { diff --git a/debugger/src/datasources.js b/debugger/src/datasources.js index ac7b14475..8eca0246d 100644 --- a/debugger/src/datasources.js +++ b/debugger/src/datasources.js @@ -87,7 +87,7 @@ module.service('DataSource', function($q) { return DataSource; }); -module.service('RemoteDataSource', function($q, DataSource) { +module.service('RemoteDataSource', function($q, log, DataSource) { var RemoteDataSource = function(url) { DataSource.call(this, url); this.url = url; @@ -121,6 +121,7 @@ module.service('RemoteDataSource', function($q, DataSource) { d.reject(e.code + ' ' + e.reason); } else { this.status = 'disconnected'; + log.info('Disconnected'); } }).bind(this); diff --git a/debugger/src/session.js b/debugger/src/session.js index fef58b745..820837cbe 100644 --- a/debugger/src/session.js +++ b/debugger/src/session.js @@ -13,7 +13,7 @@ var module = angular.module('xe.session', []); module.service('Session', function( - $q, $http, log, FileDataSource, RemoteDataSource) { + $rootScope, $q, $http, log, FileDataSource, RemoteDataSource) { var Session = function(id, opt_dataSource) { this.id = id; @@ -85,6 +85,7 @@ module.service('Session', function( if (this.dataSource) { this.dataSource.dispose(); this.dataSource = null; + $rootScope.$emit('refresh'); } }; diff --git a/src/alloy/backend/assembler.h b/src/alloy/backend/assembler.h index c42512ab1..d2e7f6c67 100644 --- a/src/alloy/backend/assembler.h +++ b/src/alloy/backend/assembler.h @@ -18,6 +18,7 @@ namespace hir { class FunctionBuilder; } namespace runtime { +class DebugInfo; class Function; class FunctionInfo; class Runtime; @@ -41,7 +42,7 @@ public: virtual int Assemble( runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder, - runtime::Function** out_function) = 0; + runtime::DebugInfo* debug_info, runtime::Function** out_function) = 0; protected: Backend* backend_; diff --git a/src/alloy/backend/ivm/ivm_assembler.cc b/src/alloy/backend/ivm/ivm_assembler.cc index 38a7d16bd..d5d0c48aa 100644 --- a/src/alloy/backend/ivm/ivm_assembler.cc +++ b/src/alloy/backend/ivm/ivm_assembler.cc @@ -53,8 +53,9 @@ void IVMAssembler::Reset() { int IVMAssembler::Assemble( FunctionInfo* symbol_info, FunctionBuilder* builder, - Function** out_function) { + DebugInfo* debug_info, Function** out_function) { IVMFunction* fn = new IVMFunction(symbol_info); + fn->set_debug_info(debug_info); TranslationContext ctx; ctx.access_callbacks = backend_->runtime()->access_callbacks(); diff --git a/src/alloy/backend/ivm/ivm_assembler.h b/src/alloy/backend/ivm/ivm_assembler.h index 37e77853a..dcf93f059 100644 --- a/src/alloy/backend/ivm/ivm_assembler.h +++ b/src/alloy/backend/ivm/ivm_assembler.h @@ -31,7 +31,7 @@ public: virtual int Assemble( runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder, - runtime::Function** out_function); + runtime::DebugInfo* debug_info, runtime::Function** out_function); private: Arena intcode_arena_; diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index ba39f2029..46c69d3cc 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : compiler_->AddPass(new passes::ContextPromotionPass()); compiler_->AddPass(new passes::SimplificationPass()); + // TODO(benvanik): run repeatedly? compiler_->AddPass(new passes::ConstantPropagationPass()); //compiler_->AddPass(new passes::TypePropagationPass()); //compiler_->AddPass(new passes::ByteSwapEliminationPass()); @@ -55,9 +57,6 @@ PPCTranslator::~PPCTranslator() { int PPCTranslator::Translate( FunctionInfo* symbol_info, Function** out_function) { - char* pre_ir = NULL; - char* post_ir = NULL; - // Scan the function to find its extents. We only need to do this if we // haven't already been provided with them from some other source. if (!symbol_info->has_end_address()) { @@ -70,13 +69,24 @@ int PPCTranslator::Translate( } } + // NOTE: we only want to do this when required, as it's expensive to build. + DebugInfo* debug_info = new DebugInfo(); + + // Stash source. + if (debug_info) { + DumpSource(symbol_info, &string_buffer_); + debug_info->set_source_disasm(string_buffer_.ToString()); + string_buffer_.Reset(); + } + // Emit function. int result = builder_->Emit(symbol_info); XEEXPECTZERO(result); - if (true) { + // Stash raw HIR. + if (debug_info) { builder_->Dump(&string_buffer_); - pre_ir = string_buffer_.ToString(); + debug_info->set_raw_hir_disasm(string_buffer_.ToString()); string_buffer_.Reset(); } @@ -84,24 +94,64 @@ int PPCTranslator::Translate( result = compiler_->Compile(builder_); XEEXPECTZERO(result); - if (true) { + // Stash optimized HIR. + if (debug_info) { builder_->Dump(&string_buffer_); - post_ir = string_buffer_.ToString(); + debug_info->set_hir_disasm(string_buffer_.ToString()); string_buffer_.Reset(); } // Assemble to backend machine code. - result = assembler_->Assemble(symbol_info, builder_, out_function); + result = assembler_->Assemble(symbol_info, builder_, debug_info, out_function); XEEXPECTZERO(result); result = 0; XECLEANUP: - if (pre_ir) xe_free(pre_ir); - if (post_ir) xe_free(post_ir); + if (result) { + delete debug_info; + } builder_->Reset(); compiler_->Reset(); assembler_->Reset(); string_buffer_.Reset(); return result; }; + +void PPCTranslator::DumpSource( + runtime::FunctionInfo* symbol_info, StringBuffer* string_buffer) { + Memory* memory = frontend_->memory(); + const uint8_t* p = memory->membase(); + + // TODO(benvanik): get/make up symbol name. + string_buffer->Append("%s fn %.8X-%.8X %s\n", + symbol_info->module()->name(), + symbol_info->address(), symbol_info->end_address(), + "(symbol name)"); + + uint64_t start_address = symbol_info->address(); + uint64_t end_address = symbol_info->end_address(); + InstrData i; + for (uint64_t address = start_address, offset = 0; address <= end_address; + address += 4, offset++) { + i.address = address; + i.code = XEGETUINT32BE(p + address); + // TODO(benvanik): find a way to avoid using the opcode tables. + i.type = GetInstrType(i.code); + + // TODO(benvanik): labels and such + + if (!i.type) { + string_buffer->Append("%.8X %.8X ???", address, i.code); + } else if (i.type->disassemble) { + ppc::InstrDisasm d; + i.type->disassemble(i, d); + std::string disasm; + d.Dump(disasm); + string_buffer->Append("%.8X %.8X %s", address, i.code, disasm.c_str()); + } else { + string_buffer->Append("%.8X %.8X %s ???", address, i.code, i.type->name); + } + string_buffer->Append("\n"); + } +} diff --git a/src/alloy/frontend/ppc/ppc_translator.h b/src/alloy/frontend/ppc/ppc_translator.h index 548b3fdeb..79e40aaf9 100644 --- a/src/alloy/frontend/ppc/ppc_translator.h +++ b/src/alloy/frontend/ppc/ppc_translator.h @@ -33,6 +33,10 @@ public: int Translate(runtime::FunctionInfo* symbol_info, runtime::Function** out_function); +private: + void DumpSource(runtime::FunctionInfo* symbol_info, + StringBuffer* string_buffer); + private: PPCFrontend* frontend_; PPCScanner* scanner_; diff --git a/src/alloy/runtime/debug_info.cc b/src/alloy/runtime/debug_info.cc new file mode 100644 index 000000000..c38587b78 --- /dev/null +++ b/src/alloy/runtime/debug_info.cc @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +using namespace alloy; +using namespace alloy::runtime; + + +DebugInfo::DebugInfo() : + source_disasm_(0), + raw_hir_disasm_(0), + hir_disasm_(0), + raw_lir_disasm_(0), + lir_disasm_(0), + machine_code_disasm_(0) { +} + +DebugInfo::~DebugInfo() { + xe_free(source_disasm_); + xe_free(raw_hir_disasm_); + xe_free(hir_disasm_); + xe_free(raw_lir_disasm_); + xe_free(lir_disasm_); + xe_free(machine_code_disasm_); +} diff --git a/src/alloy/runtime/debug_info.h b/src/alloy/runtime/debug_info.h new file mode 100644 index 000000000..96b6f5891 --- /dev/null +++ b/src/alloy/runtime/debug_info.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_RUNTIME_DEBUG_INFO_H_ +#define ALLOY_RUNTIME_DEBUG_INFO_H_ + +#include + + +namespace alloy { +namespace runtime { + + +class DebugInfo { +public: + DebugInfo(); + ~DebugInfo(); + + const char* source_disasm() const { return source_disasm_; } + void set_source_disasm(char* value) { source_disasm_ = value; } + const char* raw_hir_disasm() const { return raw_hir_disasm_; } + void set_raw_hir_disasm(char* value) { raw_hir_disasm_ = value; } + const char* hir_disasm() const { return hir_disasm_; } + void set_hir_disasm(char* value) { hir_disasm_ = value; } + const char* raw_lir_disasm() const { return raw_lir_disasm_; } + void set_raw_lir_disasm(char* value) { raw_lir_disasm_ = value; } + const char* lir_disasm() const { return lir_disasm_; } + void set_lir_disasm(char* value) { lir_disasm_ = value; } + const char* machine_code_disasm() const { return machine_code_disasm_; } + void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; } + + // map functions: source addr -> hir index (raw?) + // hir index (raw?) to lir index (raw?) + // lir index (raw?) to machine code offset + // source -> machine code offset + +private: + char* source_disasm_; + char* raw_hir_disasm_; + char* hir_disasm_; + char* raw_lir_disasm_; + char* lir_disasm_; + char* machine_code_disasm_; +}; + + +} // namespace runtime +} // namespace alloy + + +#endif // ALLOY_RUNTIME_DEBUG_INFO_H_ diff --git a/src/alloy/runtime/function.cc b/src/alloy/runtime/function.cc index c01e039ee..ca968da36 100644 --- a/src/alloy/runtime/function.cc +++ b/src/alloy/runtime/function.cc @@ -17,7 +17,7 @@ using namespace alloy::runtime; Function::Function(Type type, uint64_t address) : - type_(type), address_(address) { + type_(type), address_(address), debug_info_(0) { } Function::~Function() { diff --git a/src/alloy/runtime/function.h b/src/alloy/runtime/function.h index 0620324d3..abe51956b 100644 --- a/src/alloy/runtime/function.h +++ b/src/alloy/runtime/function.h @@ -11,6 +11,7 @@ #define ALLOY_RUNTIME_FUNCTION_H_ #include +#include namespace alloy { @@ -34,6 +35,9 @@ public: Type type() const { return type_; } uint64_t address() const { return address_; } + DebugInfo* debug_info() const { return debug_info_; } + void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; } + int Call(ThreadState* thread_state, uint64_t return_address); protected: @@ -42,6 +46,7 @@ protected: protected: Type type_; uint64_t address_; + DebugInfo* debug_info_; }; diff --git a/src/alloy/runtime/sources.gypi b/src/alloy/runtime/sources.gypi index e7f211eac..65392b319 100644 --- a/src/alloy/runtime/sources.gypi +++ b/src/alloy/runtime/sources.gypi @@ -1,6 +1,8 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'debug_info.cc', + 'debug_info.h', 'entry_table.cc', 'entry_table.h', 'function.cc', diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 8c40d14ae..aeea7374c 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -234,6 +234,11 @@ json_t* Processor::OnDebugRequest( succeeded = false; return json_string("Unable to resolve function"); } + DebugInfo* debug_info = fn->debug_info(); + if (!debug_info) { + succeeded = false; + return json_string("No debug info present for function"); + } json_t* fn_json = json_object(); // TODO(benvanik): get name @@ -249,6 +254,22 @@ json_t* Processor::OnDebugRequest( json_t* link_status_json = json_integer(info->status()); json_object_set_new(fn_json, "linkStatus", link_status_json); + json_t* disasm_json = json_object(); + json_t* disasm_str_json; + disasm_str_json = json_string(debug_info->source_disasm()); + json_object_set_new(disasm_json, "source", disasm_str_json); + disasm_str_json = json_string(debug_info->raw_hir_disasm()); + json_object_set_new(disasm_json, "rawHir", disasm_str_json); + disasm_str_json = json_string(debug_info->hir_disasm()); + json_object_set_new(disasm_json, "hir", disasm_str_json); + disasm_str_json = json_string(debug_info->raw_lir_disasm()); + json_object_set_new(disasm_json, "rawLir", disasm_str_json); + disasm_str_json = json_string(debug_info->lir_disasm()); + json_object_set_new(disasm_json, "lir", disasm_str_json); + disasm_str_json = json_string(debug_info->machine_code_disasm()); + json_object_set_new(disasm_json, "machineCode", disasm_str_json); + json_object_set_new(fn_json, "disasm", disasm_json); + delete fn; return fn_json;