From 573f190a433b5bc4ff27510089834a39e92bb1e5 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 8 Jun 2015 21:12:40 -0700 Subject: [PATCH] Adding modules/functions to the debugger. --- src/Xenia.Debug.UI/Controls/BaseDocument.cs | 2 + src/Xenia.Debug.UI/Controls/BasePanel.cs | 2 + src/Xenia.Debug.UI/MainWindow.cs | 13 +- src/Xenia.Debug.UI/Views/BreakpointsPanel.cs | 4 +- .../Views/CodeDocument.Designer.cs | 90 ++++- src/Xenia.Debug.UI/Views/CodeDocument.cs | 58 +++ .../Views/FunctionsPanel.Designer.cs | 9 +- src/Xenia.Debug.UI/Views/FunctionsPanel.cs | 73 +++- .../Views/ModulesPanel.Designer.cs | 41 +- src/Xenia.Debug.UI/Views/ModulesPanel.cs | 13 +- src/Xenia.Debug.UI/Views/ModulesPanel.resx | 12 + src/Xenia.Debug.UI/Views/ThreadsPanel.cs | 4 +- src/Xenia.Debug/Breakpoint.cs | 6 +- src/Xenia.Debug/BreakpointList.cs | 3 +- src/Xenia.Debug/Context.cs | 3 +- src/Xenia.Debug/Debugger.cs | 21 +- src/Xenia.Debug/Function.cs | 87 ++++- src/Xenia.Debug/KernelObject.cs | 3 +- src/Xenia.Debug/Memory.cs | 3 +- src/Xenia.Debug/MemoryView.cs | 3 +- src/Xenia.Debug/Module.cs | 87 ++++- src/Xenia.Debug/ModuleList.cs | 18 +- .../Proto/xe/debug/proto/Function.cs | 59 +++ .../Proto/xe/debug/proto/FunctionEntry.cs | 43 +++ .../xe/debug/proto/GetFunctionRequest.cs | 31 ++ .../xe/debug/proto/GetFunctionResponse.cs | 32 ++ .../xe/debug/proto/ListFunctionsRequest.cs | 39 ++ .../xe/debug/proto/ListFunctionsResponse.cs | 35 ++ .../Proto/xe/debug/proto/ListModuleEntry.cs | 23 ++ .../xe/debug/proto/ListModulesResponse.cs | 14 +- .../Proto/xe/debug/proto/RequestData.cs | 10 +- .../Proto/xe/debug/proto/ResponseData.cs | 14 +- src/Xenia.Debug/ThreadList.cs | 3 +- src/Xenia.Debug/Utilities/Changeable.cs | 10 +- src/Xenia.Debug/Xenia.Debug.csproj | 7 + src/xenia/apu/audio_system.cc | 2 +- src/xenia/cpu/module.cc | 24 +- src/xenia/cpu/module.h | 5 +- src/xenia/debug/debugger.cc | 146 ++++++- src/xenia/debug/proto/messages.fbs | 4 + src/xenia/debug/proto/messages_generated.h | 68 +++- src/xenia/debug/proto/modules.fbs | 43 ++- src/xenia/debug/proto/modules_generated.h | 357 +++++++++++++++++- src/xenia/kernel/objects/xkernel_module.cc | 2 +- src/xenia/kernel/objects/xmodule.cc | 8 +- src/xenia/kernel/objects/xmodule.h | 16 +- src/xenia/kernel/objects/xuser_module.cc | 5 +- 47 files changed, 1427 insertions(+), 128 deletions(-) create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/Function.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/FunctionEntry.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionRequest.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionResponse.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsRequest.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsResponse.cs create mode 100644 src/Xenia.Debug/Proto/xe/debug/proto/ListModuleEntry.cs diff --git a/src/Xenia.Debug.UI/Controls/BaseDocument.cs b/src/Xenia.Debug.UI/Controls/BaseDocument.cs index 79b96f8ac..90930261b 100644 --- a/src/Xenia.Debug.UI/Controls/BaseDocument.cs +++ b/src/Xenia.Debug.UI/Controls/BaseDocument.cs @@ -11,6 +11,8 @@ using WeifenLuo.WinFormsUI.Docking; namespace Xenia.Debug.UI.Controls { public partial class BaseDocument : DockContent { + public static MainWindow MainWindow; + public BaseDocument() { InitializeComponent(); } diff --git a/src/Xenia.Debug.UI/Controls/BasePanel.cs b/src/Xenia.Debug.UI/Controls/BasePanel.cs index 90c30589b..d3ec117ef 100644 --- a/src/Xenia.Debug.UI/Controls/BasePanel.cs +++ b/src/Xenia.Debug.UI/Controls/BasePanel.cs @@ -11,6 +11,8 @@ using WeifenLuo.WinFormsUI.Docking; namespace Xenia.Debug.UI.Controls { public partial class BasePanel : DockContent { + public static MainWindow MainWindow; + public BasePanel() { InitializeComponent(); } diff --git a/src/Xenia.Debug.UI/MainWindow.cs b/src/Xenia.Debug.UI/MainWindow.cs index 17b7ebcb4..a262fe933 100644 --- a/src/Xenia.Debug.UI/MainWindow.cs +++ b/src/Xenia.Debug.UI/MainWindow.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; +using Xenia.Debug.UI.Controls; using Xenia.Debug.UI.Views; using Xenia.Debug.Utilities; @@ -36,6 +37,9 @@ namespace Xenia.Debug.UI { public MainWindow() { InitializeComponent(); + BasePanel.MainWindow = this; + BaseDocument.MainWindow = this; + dockPanel = new DockPanel(); dockPanel.Dock = System.Windows.Forms.DockStyle.Fill; dockPanel.DockBackColor = System.Drawing.SystemColors.AppWorkspace; @@ -76,7 +80,7 @@ namespace Xenia.Debug.UI { Debugger.StateChanged += Debugger_StateChanged; Debugger_StateChanged(this, Debugger.CurrentState); Debugger.CurrentContext.Changed += CurrentContext_Changed; - CurrentContext_Changed(); + CurrentContext_Changed(Debugger.CurrentContext); Debugger.Attach(); } @@ -102,7 +106,7 @@ namespace Xenia.Debug.UI { controlToolStrip.Enabled = enabled; } - private void CurrentContext_Changed() { + private void CurrentContext_Changed(Context sender) { bool enabled = false; switch (Debugger.CurrentContext.RunState) { case RunState.Updating: @@ -157,6 +161,11 @@ namespace Xenia.Debug.UI { dockPanel.ResumeLayout(true, true); } + public void OpenFunction(Function function) { + var document = codeDocuments[0]; + document.Show(function); + } + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { //if (keyData == (Keys.Control | Keys.F)) { // MessageBox.Show("What the Ctrl+F?"); diff --git a/src/Xenia.Debug.UI/Views/BreakpointsPanel.cs b/src/Xenia.Debug.UI/Views/BreakpointsPanel.cs index ae7e02875..d4e9022a2 100644 --- a/src/Xenia.Debug.UI/Views/BreakpointsPanel.cs +++ b/src/Xenia.Debug.UI/Views/BreakpointsPanel.cs @@ -19,10 +19,10 @@ namespace Xenia.Debug.UI.Views { this.debugger = debugger; debugger.BreakpointList.Changed += UpdateBreakpointsList; - UpdateBreakpointsList(); + UpdateBreakpointsList(debugger.BreakpointList); } - private void UpdateBreakpointsList() { + private void UpdateBreakpointsList(BreakpointList sender) { breakpointsListView.BeginUpdate(); breakpointsListView.Items.Clear(); foreach (Breakpoint breakpoint in debugger.BreakpointList) { diff --git a/src/Xenia.Debug.UI/Views/CodeDocument.Designer.cs b/src/Xenia.Debug.UI/Views/CodeDocument.Designer.cs index 2a9570716..b4ba47e88 100644 --- a/src/Xenia.Debug.UI/Views/CodeDocument.Designer.cs +++ b/src/Xenia.Debug.UI/Views/CodeDocument.Designer.cs @@ -1,4 +1,6 @@ -namespace Xenia.Debug.UI.Views { +using System; + +namespace Xenia.Debug.UI.Views { partial class CodeDocument { /// /// Required designer variable. @@ -24,6 +26,12 @@ /// private void InitializeComponent() { this.sourceTextBox = new System.Windows.Forms.TextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.disasmMachineCodeCheckBox = new System.Windows.Forms.CheckBox(); + this.disasmOptimizedHirCheckBox = new System.Windows.Forms.CheckBox(); + this.disasmUnoptimizedHirCheckBox = new System.Windows.Forms.CheckBox(); + this.disasmPpcCheckBox = new System.Windows.Forms.CheckBox(); + this.panel1.SuspendLayout(); this.SuspendLayout(); // // sourceTextBox @@ -31,20 +39,93 @@ this.sourceTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.sourceTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.sourceTextBox.HideSelection = false; this.sourceTextBox.Location = new System.Drawing.Point(12, 75); + this.sourceTextBox.MaxLength = 99999; this.sourceTextBox.Multiline = true; this.sourceTextBox.Name = "sourceTextBox"; - this.sourceTextBox.Size = new System.Drawing.Size(740, 586); + this.sourceTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.sourceTextBox.Size = new System.Drawing.Size(740, 563); this.sourceTextBox.TabIndex = 0; // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.Controls.Add(this.disasmMachineCodeCheckBox); + this.panel1.Controls.Add(this.disasmOptimizedHirCheckBox); + this.panel1.Controls.Add(this.disasmUnoptimizedHirCheckBox); + this.panel1.Controls.Add(this.disasmPpcCheckBox); + this.panel1.Location = new System.Drawing.Point(12, 644); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(740, 17); + this.panel1.TabIndex = 1; + // + // disasmMachineCodeCheckBox + // + this.disasmMachineCodeCheckBox.AutoSize = true; + this.disasmMachineCodeCheckBox.Checked = true; + this.disasmMachineCodeCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.disasmMachineCodeCheckBox.Location = new System.Drawing.Point(302, 0); + this.disasmMachineCodeCheckBox.Name = "disasmMachineCodeCheckBox"; + this.disasmMachineCodeCheckBox.Size = new System.Drawing.Size(95, 17); + this.disasmMachineCodeCheckBox.TabIndex = 3; + this.disasmMachineCodeCheckBox.Text = "Machine Code"; + this.disasmMachineCodeCheckBox.UseVisualStyleBackColor = true; + this.disasmMachineCodeCheckBox.CheckedChanged += new System.EventHandler(this.DisasmCheckBoxChanged); + // + // disasmOptimizedHirCheckBox + // + this.disasmOptimizedHirCheckBox.AutoSize = true; + this.disasmOptimizedHirCheckBox.Checked = true; + this.disasmOptimizedHirCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.disasmOptimizedHirCheckBox.Location = new System.Drawing.Point(202, 0); + this.disasmOptimizedHirCheckBox.Name = "disasmOptimizedHirCheckBox"; + this.disasmOptimizedHirCheckBox.Size = new System.Drawing.Size(94, 17); + this.disasmOptimizedHirCheckBox.TabIndex = 2; + this.disasmOptimizedHirCheckBox.Text = "Optimized HIR"; + this.disasmOptimizedHirCheckBox.UseVisualStyleBackColor = true; + this.disasmOptimizedHirCheckBox.CheckedChanged += new System.EventHandler(this.DisasmCheckBoxChanged); + // + // disasmUnoptimizedHirCheckBox + // + this.disasmUnoptimizedHirCheckBox.AutoSize = true; + this.disasmUnoptimizedHirCheckBox.Checked = true; + this.disasmUnoptimizedHirCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.disasmUnoptimizedHirCheckBox.Location = new System.Drawing.Point(90, 0); + this.disasmUnoptimizedHirCheckBox.Name = "disasmUnoptimizedHirCheckBox"; + this.disasmUnoptimizedHirCheckBox.Size = new System.Drawing.Size(106, 17); + this.disasmUnoptimizedHirCheckBox.TabIndex = 1; + this.disasmUnoptimizedHirCheckBox.Text = "Unoptimized HIR"; + this.disasmUnoptimizedHirCheckBox.UseVisualStyleBackColor = true; + this.disasmUnoptimizedHirCheckBox.CheckedChanged += new System.EventHandler(this.DisasmCheckBoxChanged); + // + // disasmPpcCheckBox + // + this.disasmPpcCheckBox.AutoSize = true; + this.disasmPpcCheckBox.Checked = true; + this.disasmPpcCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.disasmPpcCheckBox.Location = new System.Drawing.Point(0, 0); + this.disasmPpcCheckBox.Name = "disasmPpcCheckBox"; + this.disasmPpcCheckBox.Size = new System.Drawing.Size(84, 17); + this.disasmPpcCheckBox.TabIndex = 0; + this.disasmPpcCheckBox.Text = "Source PPC"; + this.disasmPpcCheckBox.UseVisualStyleBackColor = true; + this.disasmPpcCheckBox.CheckedChanged += new System.EventHandler(this.DisasmCheckBoxChanged); + // // CodeDocument // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(764, 673); + this.Controls.Add(this.panel1); this.Controls.Add(this.sourceTextBox); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "CodeDocument"; this.Text = "Code"; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -53,5 +134,10 @@ #endregion private System.Windows.Forms.TextBox sourceTextBox; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.CheckBox disasmMachineCodeCheckBox; + private System.Windows.Forms.CheckBox disasmOptimizedHirCheckBox; + private System.Windows.Forms.CheckBox disasmUnoptimizedHirCheckBox; + private System.Windows.Forms.CheckBox disasmPpcCheckBox; } } \ No newline at end of file diff --git a/src/Xenia.Debug.UI/Views/CodeDocument.cs b/src/Xenia.Debug.UI/Views/CodeDocument.cs index 138b70301..508e336b5 100644 --- a/src/Xenia.Debug.UI/Views/CodeDocument.cs +++ b/src/Xenia.Debug.UI/Views/CodeDocument.cs @@ -14,9 +14,67 @@ namespace Xenia.Debug.UI.Views { public partial class CodeDocument : BaseDocument { private readonly Debugger debugger; + private Function function; + public CodeDocument(Debugger debugger) { InitializeComponent(); this.debugger = debugger; } + + public async void Show(Function function) { + this.function = function; + + this.sourceTextBox.Text = "Loading..."; + await function.Invalidate(); + + UpdateSourceTextBox(); + } + + private void UpdateSourceTextBox() { + string combinedString = ""; + + if (disasmPpcCheckBox.Checked) { + combinedString += "Source PPC" + Environment.NewLine; + if (function.DisasmPpc != null) { + combinedString += function.DisasmPpc; + } else { + combinedString += "(unavailable)"; + } + combinedString += Environment.NewLine + Environment.NewLine; + } + if (disasmUnoptimizedHirCheckBox.Checked) { + combinedString += "Unoptimized HIR" + Environment.NewLine; + if (function.DisasmHirUnoptimized != null) { + combinedString += function.DisasmHirUnoptimized; + } else { + combinedString += "(unavailable)"; + } + combinedString += Environment.NewLine + Environment.NewLine; + } + if (disasmOptimizedHirCheckBox.Checked) { + combinedString += "Optimized HIR" + Environment.NewLine; + if (function.DisasmHirOptimized != null) { + combinedString += function.DisasmHirOptimized; + } else { + combinedString += "(unavailable)"; + } + combinedString += Environment.NewLine + Environment.NewLine; + } + if (disasmMachineCodeCheckBox.Checked) { + combinedString += "Machine Code" + Environment.NewLine; + if (function.DisasmMachineCode != null) { + combinedString += function.DisasmMachineCode; + } else { + combinedString += "(unavailable)"; + } + combinedString += Environment.NewLine + Environment.NewLine; + } + + this.sourceTextBox.Text = combinedString; + } + + private void DisasmCheckBoxChanged(object sender, EventArgs e) { + UpdateSourceTextBox(); + } } } diff --git a/src/Xenia.Debug.UI/Views/FunctionsPanel.Designer.cs b/src/Xenia.Debug.UI/Views/FunctionsPanel.Designer.cs index 6ebbc7b88..726be557c 100644 --- a/src/Xenia.Debug.UI/Views/FunctionsPanel.Designer.cs +++ b/src/Xenia.Debug.UI/Views/FunctionsPanel.Designer.cs @@ -28,15 +28,17 @@ this.functionsListBox = new System.Windows.Forms.ListBox(); this.SuspendLayout(); // - // moduleComboBox + // modulesComboBox // this.modulesComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.modulesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.modulesComboBox.FormattingEnabled = true; this.modulesComboBox.Location = new System.Drawing.Point(12, 12); - this.modulesComboBox.Name = "moduleComboBox"; + this.modulesComboBox.Name = "modulesComboBox"; this.modulesComboBox.Size = new System.Drawing.Size(234, 21); this.modulesComboBox.TabIndex = 0; + this.modulesComboBox.SelectedIndexChanged += new System.EventHandler(this.modulesComboBox_SelectedIndexChanged); // // filterTextBox // @@ -48,6 +50,7 @@ this.filterTextBox.Name = "filterTextBox"; this.filterTextBox.Size = new System.Drawing.Size(234, 20); this.filterTextBox.TabIndex = 1; + this.filterTextBox.TextChanged += new System.EventHandler(this.filterTextBox_TextChanged); // // functionsListBox // @@ -59,6 +62,7 @@ this.functionsListBox.Name = "functionsListBox"; this.functionsListBox.Size = new System.Drawing.Size(234, 524); this.functionsListBox.TabIndex = 2; + this.functionsListBox.SelectedIndexChanged += new System.EventHandler(this.functionsListBox_SelectedIndexChanged); // // FunctionsPanel // @@ -68,6 +72,7 @@ this.Controls.Add(this.functionsListBox); this.Controls.Add(this.filterTextBox); this.Controls.Add(this.modulesComboBox); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "FunctionsPanel"; this.Text = "Functions"; this.ResumeLayout(false); diff --git a/src/Xenia.Debug.UI/Views/FunctionsPanel.cs b/src/Xenia.Debug.UI/Views/FunctionsPanel.cs index c2dc25ceb..80555caa6 100644 --- a/src/Xenia.Debug.UI/Views/FunctionsPanel.cs +++ b/src/Xenia.Debug.UI/Views/FunctionsPanel.cs @@ -18,17 +18,84 @@ namespace Xenia.Debug.UI.Views { InitializeComponent(); this.debugger = debugger; + RefreshFunctionList(); + debugger.ModuleList.Changed += UpdateModulesList; - UpdateModulesList(); + UpdateModulesList(debugger.ModuleList); } - private void UpdateModulesList() { + private void UpdateModulesList(ModuleList sender) { modulesComboBox.BeginUpdate(); modulesComboBox.Items.Clear(); foreach (Module module in debugger.ModuleList) { - modulesComboBox.Items.Add("Module A"); + modulesComboBox.Items.Add(module); + module.Changed += Module_Changed; } modulesComboBox.EndUpdate(); } + + private void Module_Changed(KernelObject sender) { + if (modulesComboBox.SelectedItem != sender) { + return; + } + + RefreshFunctionList(); + } + + private void modulesComboBox_SelectedIndexChanged(object sender, EventArgs e) { + if (modulesComboBox.SelectedItem == null) { + return; + } + var module = (Module)modulesComboBox.SelectedItem; + + RefreshFunctionList(); + } + + private void RefreshFunctionList() { + if (modulesComboBox.SelectedItem == null) { + functionsListBox.Items.Clear(); + functionsListBox.Enabled = false; + filterTextBox.Enabled = false; + return; + } + functionsListBox.Enabled = true; + filterTextBox.Enabled = true; + var module = (Module)modulesComboBox.SelectedItem; + + functionsListBox.BeginUpdate(); + functionsListBox.Items.Clear(); + + foreach (Function function in module) { + functionsListBox.Items.Add(function); + } + + functionsListBox.EndUpdate(); + } + + private void filterTextBox_TextChanged(object sender, EventArgs e) { + var module = (Module)modulesComboBox.SelectedItem; + + var filter = filterTextBox.Text.ToLowerInvariant(); + + functionsListBox.BeginUpdate(); + functionsListBox.Items.Clear(); + + foreach (Function function in module) { + if (filter.Length == 0 || function.LowerName.Contains(filter)) { + functionsListBox.Items.Add(function); + } + } + + functionsListBox.EndUpdate(); + } + + private void functionsListBox_SelectedIndexChanged(object sender, EventArgs e) { + var function = (Function)functionsListBox.SelectedItem; + if (function == null) { + return; + } + + MainWindow.OpenFunction(function); + } } } diff --git a/src/Xenia.Debug.UI/Views/ModulesPanel.Designer.cs b/src/Xenia.Debug.UI/Views/ModulesPanel.Designer.cs index ba7e8e824..7e68fe63c 100644 --- a/src/Xenia.Debug.UI/Views/ModulesPanel.Designer.cs +++ b/src/Xenia.Debug.UI/Views/ModulesPanel.Designer.cs @@ -23,10 +23,15 @@ /// the contents of this method with the code editor. /// private void InitializeComponent() { + System.Windows.Forms.ColumnHeader columnHeader1; + System.Windows.Forms.ColumnHeader columnHeader2; + System.Windows.Forms.ColumnHeader columnHeader3; + System.Windows.Forms.ColumnHeader columnHeader4; this.modulesListView = new System.Windows.Forms.ListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.SuspendLayout(); // // modulesListView @@ -35,9 +40,10 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.modulesListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader2, - this.columnHeader3}); + columnHeader1, + columnHeader2, + columnHeader3, + columnHeader4}); this.modulesListView.Location = new System.Drawing.Point(12, 12); this.modulesListView.Name = "modulesListView"; this.modulesListView.Size = new System.Drawing.Size(748, 206); @@ -45,12 +51,32 @@ this.modulesListView.UseCompatibleStateImageBehavior = false; this.modulesListView.View = System.Windows.Forms.View.Details; // + // columnHeader1 + // + columnHeader1.Text = "Handle"; + // + // columnHeader2 + // + columnHeader2.Text = "Type"; + columnHeader2.Width = 80; + // + // columnHeader3 + // + columnHeader3.Text = "Name"; + columnHeader3.Width = 120; + // + // columnHeader4 + // + columnHeader4.Text = "Path"; + columnHeader4.Width = 300; + // // ModulesPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(772, 230); this.Controls.Add(this.modulesListView); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "ModulesPanel"; this.Text = "Modules"; this.ResumeLayout(false); @@ -60,8 +86,5 @@ #endregion private System.Windows.Forms.ListView modulesListView; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.ColumnHeader columnHeader3; } } \ No newline at end of file diff --git a/src/Xenia.Debug.UI/Views/ModulesPanel.cs b/src/Xenia.Debug.UI/Views/ModulesPanel.cs index ff9fe72f0..18ddc0c29 100644 --- a/src/Xenia.Debug.UI/Views/ModulesPanel.cs +++ b/src/Xenia.Debug.UI/Views/ModulesPanel.cs @@ -19,14 +19,21 @@ namespace Xenia.Debug.UI.Views { this.debugger = debugger; debugger.ModuleList.Changed += UpdateModulesList; - UpdateModulesList(); + UpdateModulesList(debugger.ModuleList); } - private void UpdateModulesList() { + private void UpdateModulesList(ModuleList sender) { modulesListView.BeginUpdate(); modulesListView.Items.Clear(); foreach (Module module in debugger.ModuleList) { - modulesListView.Items.Add("Module A"); + var item = new ListViewItem(new string[]{ + module.Handle.ToString("X4"), + module.ModuleType == xe.debug.proto.ModuleType.Kernel ? "Kernel" + : "User", + module.Name, + module.Path, + }); + modulesListView.Items.Add(item); } modulesListView.EndUpdate(); } diff --git a/src/Xenia.Debug.UI/Views/ModulesPanel.resx b/src/Xenia.Debug.UI/Views/ModulesPanel.resx index 1af7de150..9ebd52322 100644 --- a/src/Xenia.Debug.UI/Views/ModulesPanel.resx +++ b/src/Xenia.Debug.UI/Views/ModulesPanel.resx @@ -117,4 +117,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + False + + + False + + + False + + + False + \ No newline at end of file diff --git a/src/Xenia.Debug.UI/Views/ThreadsPanel.cs b/src/Xenia.Debug.UI/Views/ThreadsPanel.cs index 0357b2aa8..bd6784d8a 100644 --- a/src/Xenia.Debug.UI/Views/ThreadsPanel.cs +++ b/src/Xenia.Debug.UI/Views/ThreadsPanel.cs @@ -19,10 +19,10 @@ namespace Xenia.Debug.UI.Views { this.debugger = debugger; debugger.ThreadList.Changed += UpdateThreadList; - UpdateThreadList(); + UpdateThreadList(debugger.ThreadList); } - private void UpdateThreadList() { + private void UpdateThreadList(ThreadList sender) { threadsListView.BeginUpdate(); threadsListView.Items.Clear(); foreach (Thread thread in debugger.ThreadList) { diff --git a/src/Xenia.Debug/Breakpoint.cs b/src/Xenia.Debug/Breakpoint.cs index 4412f5bff..43cb39e57 100644 --- a/src/Xenia.Debug/Breakpoint.cs +++ b/src/Xenia.Debug/Breakpoint.cs @@ -6,10 +6,14 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class Breakpoint : Changeable { + public class Breakpoint : Changeable { // type code/data/kernel // address+[end address] // conditions? script? // action (suspend, trace, etc) + + public Breakpoint() { + this.self = this; + } } } diff --git a/src/Xenia.Debug/BreakpointList.cs b/src/Xenia.Debug/BreakpointList.cs index d7adf5c4b..e0bc303d2 100644 --- a/src/Xenia.Debug/BreakpointList.cs +++ b/src/Xenia.Debug/BreakpointList.cs @@ -7,11 +7,12 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class BreakpointList : Changeable, IReadOnlyCollection { + public class BreakpointList : Changeable, IReadOnlyCollection { private readonly Debugger debugger; private readonly List breakpoints = new List(); public BreakpointList(Debugger debugger) { + this.self = this; this.debugger = debugger; } diff --git a/src/Xenia.Debug/Context.cs b/src/Xenia.Debug/Context.cs index 762f3e6d9..853147e46 100644 --- a/src/Xenia.Debug/Context.cs +++ b/src/Xenia.Debug/Context.cs @@ -12,10 +12,11 @@ namespace Xenia.Debug { Paused, } - public class Context : Changeable { + public class Context : Changeable { private readonly Debugger debugger; public Context(Debugger debugger) { + this.self = this; this.debugger = debugger; } diff --git a/src/Xenia.Debug/Debugger.cs b/src/Xenia.Debug/Debugger.cs index 212a762df..0d1818d5d 100644 --- a/src/Xenia.Debug/Debugger.cs +++ b/src/Xenia.Debug/Debugger.cs @@ -193,14 +193,19 @@ namespace Xenia.Debug { // Read body. var bodyBuffer = new byte[length]; - receiveLength = await Task.Factory.FromAsync( - (callback, state) => socket.BeginReceive(bodyBuffer, 0, bodyBuffer.Length, SocketFlags.None, callback, state), - asyncResult => socket.EndReceive(asyncResult), - null); - if (receiveLength == 0 || receiveLength != bodyBuffer.Length) { - // Failed? - ReceivePump(); - return; + int bodyOffset = 0; + while (bodyOffset != bodyBuffer.Length) { + receiveLength = await Task.Factory.FromAsync( + (callback, state) => socket.BeginReceive( + bodyBuffer, bodyOffset, bodyBuffer.Length - bodyOffset, + SocketFlags.None, callback, state), + asyncResult => socket.EndReceive(asyncResult), null); + if (receiveLength == 0) { + // Failed? + ReceivePump(); + return; + } + bodyOffset += receiveLength; } // Emit message. diff --git a/src/Xenia.Debug/Function.cs b/src/Xenia.Debug/Function.cs index 63170f899..913f6413a 100644 --- a/src/Xenia.Debug/Function.cs +++ b/src/Xenia.Debug/Function.cs @@ -3,18 +3,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using xe.debug.proto; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class Function : Changeable { + public class Function : Changeable { // status: declared, defined, failed - // module - // name - // startAddress - // endAddress // behavior: default, prolog, epilog, epilog_return, extern // extern info? + public readonly Debugger Debugger; + public readonly Module Module; + public readonly ulong Identifier; + public readonly uint AddressStart; + public readonly uint AddressEnd; + // source map // disasm: @@ -29,5 +32,79 @@ namespace Xenia.Debug { // call count // caller history // instruction execution counts + + public string DisasmPpc { + get; private set; + } + public string DisasmHirUnoptimized { + get; private set; + } + public string DisasmHirOptimized { + get; private set; + } + public string DisasmMachineCode { + get; private set; + } + + public Function(Debugger debugger, Module module, xe.debug.proto.FunctionEntry functionEntry) { + this.self = this; + this.Debugger = debugger; + this.Module = module; + Identifier = functionEntry.Identifier; + AddressStart = functionEntry.AddressStart; + AddressEnd = functionEntry.AddressEnd; + Name = functionEntry.Name; + } + + private string name; + public string Name { + get { + return name; + } + set { + name = value; + if (value == null) { + name = "sub_" + AddressStart.ToString("X8"); + } + LowerName = name.ToLowerInvariant(); + } + } + public string LowerName { + get; set; + } + + public override string ToString() { + return Name; + } + + public async Task Invalidate() { + var fbb = Debugger.BeginRequest(); + int requestDataOffset = GetFunctionRequest.CreateGetFunctionRequest(fbb, Identifier); + var response = await Debugger.CommitRequest( + fbb, RequestData.GetFunctionRequest, requestDataOffset); + + var responseData = new GetFunctionResponse(); + response.GetResponseData(responseData); + var functionData = responseData.Function; + + this.DisasmPpc = functionData.DisasmPpc; + this.DisasmHirUnoptimized = functionData.DisasmHirRaw; + this.DisasmHirOptimized = functionData.DisasmHirOpt; + this.DisasmMachineCode = functionData.DisasmMachineCode; + if (DisasmPpc != null) { + DisasmPpc = DisasmPpc.Replace("\n", "\r\n"); + } + if (DisasmHirUnoptimized != null) { + DisasmHirUnoptimized = DisasmHirUnoptimized.Replace("\n", "\r\n"); + } + if (DisasmHirOptimized != null) { + DisasmHirOptimized = DisasmHirOptimized.Replace("\n", "\r\n"); + } + if (DisasmMachineCode != null) { + DisasmMachineCode = DisasmMachineCode.Replace("\n", "\r\n"); + } + + OnChanged(); + } } } diff --git a/src/Xenia.Debug/KernelObject.cs b/src/Xenia.Debug/KernelObject.cs index 0a70e3988..55035e98a 100644 --- a/src/Xenia.Debug/KernelObject.cs +++ b/src/Xenia.Debug/KernelObject.cs @@ -6,11 +6,12 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class KernelObject : Changeable { + public class KernelObject : Changeable { public readonly Debugger Debugger; public readonly uint Handle; public KernelObject(Debugger debugger, uint handle) { + this.self = this; this.Debugger = debugger; this.Handle = handle; } diff --git a/src/Xenia.Debug/Memory.cs b/src/Xenia.Debug/Memory.cs index 979e864bb..44dd9328c 100644 --- a/src/Xenia.Debug/Memory.cs +++ b/src/Xenia.Debug/Memory.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class Memory : Changeable, IDisposable { + public class Memory : Changeable, IDisposable { private readonly Debugger debugger; private class MapInfo { @@ -41,6 +41,7 @@ namespace Xenia.Debug { public UIntPtr PhysicalMembase; public Memory(Debugger debugger) { + this.self = this; this.debugger = debugger; } diff --git a/src/Xenia.Debug/MemoryView.cs b/src/Xenia.Debug/MemoryView.cs index e15969a9e..7c2dc9e57 100644 --- a/src/Xenia.Debug/MemoryView.cs +++ b/src/Xenia.Debug/MemoryView.cs @@ -6,10 +6,11 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class MemoryView : Changeable { + public class MemoryView : Changeable { private readonly Memory memory; public MemoryView(Memory memory) { + this.self = this; this.memory = memory; } diff --git a/src/Xenia.Debug/Module.cs b/src/Xenia.Debug/Module.cs index faa779154..9e0928bd3 100644 --- a/src/Xenia.Debug/Module.cs +++ b/src/Xenia.Debug/Module.cs @@ -9,26 +9,95 @@ using Xenia.Debug.Utilities; namespace Xenia.Debug { public class Module : KernelObject, IReadOnlyCollection { + private bool hasFetched = false; + private uint functionCount = 0; private readonly List functions = new List(); - // xobject: handle - // path - // type: user, kernel - // if user: - // xex header? - public Module(Debugger debugger, uint moduleHandle) : base(debugger, moduleHandle) { } - public async Task Invalidate() { + public async Task Invalidate(uint newFunctionCount) { + if (hasFetched && newFunctionCount == functionCount) { + // No-op. + return; + } + + var pendingTasks = new List(); + + if (!hasFetched) { + pendingTasks.Add(InvalidateModule()); + hasFetched = true; + } + + if (newFunctionCount != functionCount) { + uint functionIndexStart = functionCount; + uint functionIndexEnd = newFunctionCount - 1; + functionCount = newFunctionCount; + pendingTasks.Add(InvalidateFunctions(functionIndexStart, functionIndexEnd)); + } + + await Task.WhenAll(pendingTasks); + + OnChanged(); + } + + private async Task InvalidateModule() { var fbb = Debugger.BeginRequest(); int requestDataOffset = GetModuleRequest.CreateGetModuleRequest(fbb, Handle); var response = await Debugger.CommitRequest( fbb, RequestData.GetModuleRequest, requestDataOffset); - GetModuleResponse responseData = new GetModuleResponse(); + + var responseData = new GetModuleResponse(); response.GetResponseData(responseData); - // + ModuleType = responseData.Module.Type; + Name = responseData.Module.Name; + Path = responseData.Module.Path; + } + + private async Task InvalidateFunctions(uint functionIndexStart, uint functionIndexEnd) { + var fbb = Debugger.BeginRequest(); + int requestDataOffset = ListFunctionsRequest.CreateListFunctionsRequest( + fbb, Handle, functionIndexStart, functionIndexEnd); + var response = await Debugger.CommitRequest( + fbb, RequestData.ListFunctionsRequest, requestDataOffset); + + var responseData = new ListFunctionsResponse(); + response.GetResponseData(responseData); + + var functionEntry = new xe.debug.proto.FunctionEntry(); + for (int i = 0; i < responseData.EntryLength; ++i) { + responseData.GetEntry(functionEntry, i); + var function = new Function(Debugger, this, functionEntry); + functions.Add(function); + } + + functions.Sort((Function a, Function b) => { + return (int)((long)a.AddressStart - (long)b.AddressStart); + }); + } + + public ModuleType ModuleType { + get; + private set; + } + + public string Name { + get; + private set; + } + + public string Path { + get; + private set; + } + + public override string ToString() { + return ToShortString(); + } + + public string ToShortString() { + return string.Format("[{0:X4}] {1}", Handle, Name); } public int Count { diff --git a/src/Xenia.Debug/ModuleList.cs b/src/Xenia.Debug/ModuleList.cs index f68d14589..3919891ca 100644 --- a/src/Xenia.Debug/ModuleList.cs +++ b/src/Xenia.Debug/ModuleList.cs @@ -8,11 +8,12 @@ using xe.debug.proto; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class ModuleList : Changeable, IReadOnlyCollection { + public class ModuleList : Changeable, IReadOnlyCollection { private readonly Debugger debugger; private readonly List modules = new List(); public ModuleList(Debugger debugger) { + this.self = this; this.debugger = debugger; } @@ -26,20 +27,23 @@ namespace Xenia.Debug { response.GetResponseData(responseData); var pendingTasks = new List(); - for (int i = 0; i < responseData.ModuleIdsLength; ++i) { - uint moduleHandle = responseData.GetModuleIds(i); - var module = modules.Find((m) => m.Handle == moduleHandle); + for (int i = 0; i < responseData.EntryLength; ++i) { + var moduleEntry = responseData.GetEntry(i); + var module = modules.Find((m) => m.Handle == moduleEntry.Handle); if (module == null) { // Module not found. - module = new Module(debugger, moduleHandle); - pendingTasks.Add(module.Invalidate()); + module = new Module(debugger, moduleEntry.Handle); + pendingTasks.Add(module.Invalidate(moduleEntry.FunctionCount)); + modules.Add(module); } else { // Module already present. - // Modules are immutable, so ignore? + pendingTasks.Add(module.Invalidate(moduleEntry.FunctionCount)); } } await Task.WhenAll(pendingTasks); + + OnChanged(); } public int Count { diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/Function.cs b/src/Xenia.Debug/Proto/xe/debug/proto/Function.cs new file mode 100644 index 000000000..939737021 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/Function.cs @@ -0,0 +1,59 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class Function : Table { + public static Function GetRootAsFunction(ByteBuffer _bb) { return GetRootAsFunction(_bb, new Function()); } + public static Function GetRootAsFunction(ByteBuffer _bb, Function obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public Function __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public ulong Identifier { get { int o = __offset(4); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } + public uint AddressStart { get { int o = __offset(6); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public uint AddressEnd { get { int o = __offset(8); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } } + public string DisasmPpc { get { int o = __offset(12); return o != 0 ? __string(o + bb_pos) : null; } } + public string DisasmHirRaw { get { int o = __offset(14); return o != 0 ? __string(o + bb_pos) : null; } } + public string DisasmHirOpt { get { int o = __offset(16); return o != 0 ? __string(o + bb_pos) : null; } } + public string DisasmMachineCode { get { int o = __offset(18); return o != 0 ? __string(o + bb_pos) : null; } } + + public static int CreateFunction(FlatBufferBuilder builder, + ulong identifier = 0, + uint address_start = 0, + uint address_end = 0, + int name = 0, + int disasm_ppc = 0, + int disasm_hir_raw = 0, + int disasm_hir_opt = 0, + int disasm_machine_code = 0) { + builder.StartObject(8); + Function.AddIdentifier(builder, identifier); + Function.AddDisasmMachineCode(builder, disasm_machine_code); + Function.AddDisasmHirOpt(builder, disasm_hir_opt); + Function.AddDisasmHirRaw(builder, disasm_hir_raw); + Function.AddDisasmPpc(builder, disasm_ppc); + Function.AddName(builder, name); + Function.AddAddressEnd(builder, address_end); + Function.AddAddressStart(builder, address_start); + return Function.EndFunction(builder); + } + + public static void StartFunction(FlatBufferBuilder builder) { builder.StartObject(8); } + public static void AddIdentifier(FlatBufferBuilder builder, ulong identifier) { builder.AddUlong(0, identifier, 0); } + public static void AddAddressStart(FlatBufferBuilder builder, uint addressStart) { builder.AddUint(1, addressStart, 0); } + public static void AddAddressEnd(FlatBufferBuilder builder, uint addressEnd) { builder.AddUint(2, addressEnd, 0); } + public static void AddName(FlatBufferBuilder builder, int nameOffset) { builder.AddOffset(3, nameOffset, 0); } + public static void AddDisasmPpc(FlatBufferBuilder builder, int disasmPpcOffset) { builder.AddOffset(4, disasmPpcOffset, 0); } + public static void AddDisasmHirRaw(FlatBufferBuilder builder, int disasmHirRawOffset) { builder.AddOffset(5, disasmHirRawOffset, 0); } + public static void AddDisasmHirOpt(FlatBufferBuilder builder, int disasmHirOptOffset) { builder.AddOffset(6, disasmHirOptOffset, 0); } + public static void AddDisasmMachineCode(FlatBufferBuilder builder, int disasmMachineCodeOffset) { builder.AddOffset(7, disasmMachineCodeOffset, 0); } + public static int EndFunction(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/FunctionEntry.cs b/src/Xenia.Debug/Proto/xe/debug/proto/FunctionEntry.cs new file mode 100644 index 000000000..2c8678db6 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/FunctionEntry.cs @@ -0,0 +1,43 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class FunctionEntry : Table { + public static FunctionEntry GetRootAsFunctionEntry(ByteBuffer _bb) { return GetRootAsFunctionEntry(_bb, new FunctionEntry()); } + public static FunctionEntry GetRootAsFunctionEntry(ByteBuffer _bb, FunctionEntry obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public FunctionEntry __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public ulong Identifier { get { int o = __offset(4); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } + public uint AddressStart { get { int o = __offset(6); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public uint AddressEnd { get { int o = __offset(8); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } } + + public static int CreateFunctionEntry(FlatBufferBuilder builder, + ulong identifier = 0, + uint address_start = 0, + uint address_end = 0, + int name = 0) { + builder.StartObject(4); + FunctionEntry.AddIdentifier(builder, identifier); + FunctionEntry.AddName(builder, name); + FunctionEntry.AddAddressEnd(builder, address_end); + FunctionEntry.AddAddressStart(builder, address_start); + return FunctionEntry.EndFunctionEntry(builder); + } + + public static void StartFunctionEntry(FlatBufferBuilder builder) { builder.StartObject(4); } + public static void AddIdentifier(FlatBufferBuilder builder, ulong identifier) { builder.AddUlong(0, identifier, 0); } + public static void AddAddressStart(FlatBufferBuilder builder, uint addressStart) { builder.AddUint(1, addressStart, 0); } + public static void AddAddressEnd(FlatBufferBuilder builder, uint addressEnd) { builder.AddUint(2, addressEnd, 0); } + public static void AddName(FlatBufferBuilder builder, int nameOffset) { builder.AddOffset(3, nameOffset, 0); } + public static int EndFunctionEntry(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionRequest.cs b/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionRequest.cs new file mode 100644 index 000000000..811b62195 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionRequest.cs @@ -0,0 +1,31 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class GetFunctionRequest : Table { + public static GetFunctionRequest GetRootAsGetFunctionRequest(ByteBuffer _bb) { return GetRootAsGetFunctionRequest(_bb, new GetFunctionRequest()); } + public static GetFunctionRequest GetRootAsGetFunctionRequest(ByteBuffer _bb, GetFunctionRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public GetFunctionRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public ulong Identifier { get { int o = __offset(4); return o != 0 ? bb.GetUlong(o + bb_pos) : (ulong)0; } } + + public static int CreateGetFunctionRequest(FlatBufferBuilder builder, + ulong identifier = 0) { + builder.StartObject(1); + GetFunctionRequest.AddIdentifier(builder, identifier); + return GetFunctionRequest.EndGetFunctionRequest(builder); + } + + public static void StartGetFunctionRequest(FlatBufferBuilder builder) { builder.StartObject(1); } + public static void AddIdentifier(FlatBufferBuilder builder, ulong identifier) { builder.AddUlong(0, identifier, 0); } + public static int EndGetFunctionRequest(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionResponse.cs b/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionResponse.cs new file mode 100644 index 000000000..d380ba848 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/GetFunctionResponse.cs @@ -0,0 +1,32 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class GetFunctionResponse : Table { + public static GetFunctionResponse GetRootAsGetFunctionResponse(ByteBuffer _bb) { return GetRootAsGetFunctionResponse(_bb, new GetFunctionResponse()); } + public static GetFunctionResponse GetRootAsGetFunctionResponse(ByteBuffer _bb, GetFunctionResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public GetFunctionResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public Function Function { get { return GetFunction(new Function()); } } + public Function GetFunction(Function obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } + + public static int CreateGetFunctionResponse(FlatBufferBuilder builder, + int function = 0) { + builder.StartObject(1); + GetFunctionResponse.AddFunction(builder, function); + return GetFunctionResponse.EndGetFunctionResponse(builder); + } + + public static void StartGetFunctionResponse(FlatBufferBuilder builder) { builder.StartObject(1); } + public static void AddFunction(FlatBufferBuilder builder, int functionOffset) { builder.AddOffset(0, functionOffset, 0); } + public static int EndGetFunctionResponse(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsRequest.cs b/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsRequest.cs new file mode 100644 index 000000000..a5db92929 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsRequest.cs @@ -0,0 +1,39 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class ListFunctionsRequest : Table { + public static ListFunctionsRequest GetRootAsListFunctionsRequest(ByteBuffer _bb) { return GetRootAsListFunctionsRequest(_bb, new ListFunctionsRequest()); } + public static ListFunctionsRequest GetRootAsListFunctionsRequest(ByteBuffer _bb, ListFunctionsRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public ListFunctionsRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public uint ModuleId { get { int o = __offset(4); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public uint FunctionIndexStart { get { int o = __offset(6); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + public uint FunctionIndexEnd { get { int o = __offset(8); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } } + + public static int CreateListFunctionsRequest(FlatBufferBuilder builder, + uint module_id = 0, + uint function_index_start = 0, + uint function_index_end = 0) { + builder.StartObject(3); + ListFunctionsRequest.AddFunctionIndexEnd(builder, function_index_end); + ListFunctionsRequest.AddFunctionIndexStart(builder, function_index_start); + ListFunctionsRequest.AddModuleId(builder, module_id); + return ListFunctionsRequest.EndListFunctionsRequest(builder); + } + + public static void StartListFunctionsRequest(FlatBufferBuilder builder) { builder.StartObject(3); } + public static void AddModuleId(FlatBufferBuilder builder, uint moduleId) { builder.AddUint(0, moduleId, 0); } + public static void AddFunctionIndexStart(FlatBufferBuilder builder, uint functionIndexStart) { builder.AddUint(1, functionIndexStart, 0); } + public static void AddFunctionIndexEnd(FlatBufferBuilder builder, uint functionIndexEnd) { builder.AddUint(2, functionIndexEnd, 0); } + public static int EndListFunctionsRequest(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsResponse.cs b/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsResponse.cs new file mode 100644 index 000000000..22edf0de0 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/ListFunctionsResponse.cs @@ -0,0 +1,35 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class ListFunctionsResponse : Table { + public static ListFunctionsResponse GetRootAsListFunctionsResponse(ByteBuffer _bb) { return GetRootAsListFunctionsResponse(_bb, new ListFunctionsResponse()); } + public static ListFunctionsResponse GetRootAsListFunctionsResponse(ByteBuffer _bb, ListFunctionsResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public ListFunctionsResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public FunctionEntry GetEntry(int j) { return GetEntry(new FunctionEntry(), j); } + public FunctionEntry GetEntry(FunctionEntry obj, int j) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; } + public int EntryLength { get { int o = __offset(4); return o != 0 ? __vector_len(o) : 0; } } + + public static int CreateListFunctionsResponse(FlatBufferBuilder builder, + int entry = 0) { + builder.StartObject(1); + ListFunctionsResponse.AddEntry(builder, entry); + return ListFunctionsResponse.EndListFunctionsResponse(builder); + } + + public static void StartListFunctionsResponse(FlatBufferBuilder builder) { builder.StartObject(1); } + public static void AddEntry(FlatBufferBuilder builder, int entryOffset) { builder.AddOffset(0, entryOffset, 0); } + public static int CreateEntryVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); } + public static void StartEntryVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static int EndListFunctionsResponse(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return o; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/ListModuleEntry.cs b/src/Xenia.Debug/Proto/xe/debug/proto/ListModuleEntry.cs new file mode 100644 index 000000000..225ab1995 --- /dev/null +++ b/src/Xenia.Debug/Proto/xe/debug/proto/ListModuleEntry.cs @@ -0,0 +1,23 @@ +// automatically generated, do not modify + +namespace xe.debug.proto +{ + +using FlatBuffers; + +public sealed class ListModuleEntry : Struct { + public ListModuleEntry __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public uint Handle { get { return bb.GetUint(bb_pos + 0); } } + public uint FunctionCount { get { return bb.GetUint(bb_pos + 4); } } + + public static int CreateListModuleEntry(FlatBufferBuilder builder, uint Handle, uint FunctionCount) { + builder.Prep(4, 8); + builder.PutUint(FunctionCount); + builder.PutUint(Handle); + return builder.Offset; + } +}; + + +} diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/ListModulesResponse.cs b/src/Xenia.Debug/Proto/xe/debug/proto/ListModulesResponse.cs index adc2c0e7d..65d3fff2a 100644 --- a/src/Xenia.Debug/Proto/xe/debug/proto/ListModulesResponse.cs +++ b/src/Xenia.Debug/Proto/xe/debug/proto/ListModulesResponse.cs @@ -10,20 +10,20 @@ public sealed class ListModulesResponse : Table { public static ListModulesResponse GetRootAsListModulesResponse(ByteBuffer _bb, ListModulesResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } public ListModulesResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } - public uint GetModuleIds(int j) { int o = __offset(4); return o != 0 ? bb.GetUint(__vector(o) + j * 4) : (uint)0; } - public int ModuleIdsLength { get { int o = __offset(4); return o != 0 ? __vector_len(o) : 0; } } + public ListModuleEntry GetEntry(int j) { return GetEntry(new ListModuleEntry(), j); } + public ListModuleEntry GetEntry(ListModuleEntry obj, int j) { int o = __offset(4); return o != 0 ? obj.__init(__vector(o) + j * 8, bb) : null; } + public int EntryLength { get { int o = __offset(4); return o != 0 ? __vector_len(o) : 0; } } public static int CreateListModulesResponse(FlatBufferBuilder builder, - int module_ids = 0) { + int entry = 0) { builder.StartObject(1); - ListModulesResponse.AddModuleIds(builder, module_ids); + ListModulesResponse.AddEntry(builder, entry); return ListModulesResponse.EndListModulesResponse(builder); } public static void StartListModulesResponse(FlatBufferBuilder builder) { builder.StartObject(1); } - public static void AddModuleIds(FlatBufferBuilder builder, int moduleIdsOffset) { builder.AddOffset(0, moduleIdsOffset, 0); } - public static int CreateModuleIdsVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } - public static void StartModuleIdsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddEntry(FlatBufferBuilder builder, int entryOffset) { builder.AddOffset(0, entryOffset, 0); } + public static void StartEntryVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); } public static int EndListModulesResponse(FlatBufferBuilder builder) { int o = builder.EndObject(); return o; diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs b/src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs index 6bd9343c4..d76d6b417 100644 --- a/src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs +++ b/src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs @@ -13,10 +13,12 @@ public enum RequestData : byte RemoveBreakpointsRequest = 5, ListModulesRequest = 6, GetModuleRequest = 7, - StopRequest = 8, - BreakRequest = 9, - ContinueRequest = 10, - StepRequest = 11, + ListFunctionsRequest = 8, + GetFunctionRequest = 9, + StopRequest = 10, + BreakRequest = 11, + ContinueRequest = 12, + StepRequest = 13, }; diff --git a/src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs b/src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs index 9c9380bef..e7bec17f4 100644 --- a/src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs +++ b/src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs @@ -13,12 +13,14 @@ public enum ResponseData : byte RemoveBreakpointsResponse = 5, ListModulesResponse = 6, GetModuleResponse = 7, - StopResponse = 8, - BreakResponse = 9, - ContinueResponse = 10, - StepResponse = 11, - BreakpointEvent = 12, - AccessViolationEvent = 13, + ListFunctionsResponse = 8, + GetFunctionResponse = 9, + StopResponse = 10, + BreakResponse = 11, + ContinueResponse = 12, + StepResponse = 13, + BreakpointEvent = 14, + AccessViolationEvent = 15, }; diff --git a/src/Xenia.Debug/ThreadList.cs b/src/Xenia.Debug/ThreadList.cs index 099e65311..09e1a514c 100644 --- a/src/Xenia.Debug/ThreadList.cs +++ b/src/Xenia.Debug/ThreadList.cs @@ -7,11 +7,12 @@ using System.Threading.Tasks; using Xenia.Debug.Utilities; namespace Xenia.Debug { - public class ThreadList : Changeable, IReadOnlyCollection { + public class ThreadList : Changeable, IReadOnlyCollection { private readonly Debugger debugger; private readonly List threads = new List(); public ThreadList(Debugger debugger) { + this.self = this; this.debugger = debugger; } diff --git a/src/Xenia.Debug/Utilities/Changeable.cs b/src/Xenia.Debug/Utilities/Changeable.cs index fe527782c..b32057775 100644 --- a/src/Xenia.Debug/Utilities/Changeable.cs +++ b/src/Xenia.Debug/Utilities/Changeable.cs @@ -5,11 +5,13 @@ using System.Text; using System.Threading.Tasks; namespace Xenia.Debug.Utilities { - public delegate void ChangedEventHandler(); + public delegate void ChangedEventHandler(T sender); - public class Changeable { + public class Changeable { + protected T self; private int changeDepth; - public event ChangedEventHandler Changed; + + public event ChangedEventHandler Changed; protected void BeginChanging() { ++changeDepth; @@ -24,7 +26,7 @@ namespace Xenia.Debug.Utilities { protected void OnChanged() { System.Diagnostics.Debug.Assert(changeDepth == 0); if (Changed != null) { - Changed(); + Changed(self); } } } diff --git a/src/Xenia.Debug/Xenia.Debug.csproj b/src/Xenia.Debug/Xenia.Debug.csproj index 45fb6e891..8bd96dc71 100644 --- a/src/Xenia.Debug/Xenia.Debug.csproj +++ b/src/Xenia.Debug/Xenia.Debug.csproj @@ -84,10 +84,17 @@ + + + + + + + diff --git a/src/xenia/apu/audio_system.cc b/src/xenia/apu/audio_system.cc index ee1f3c875..23fc8f48d 100644 --- a/src/xenia/apu/audio_system.cc +++ b/src/xenia/apu/audio_system.cc @@ -201,7 +201,7 @@ void AudioSystem::WorkerThreadMain() { void AudioSystem::DecoderThreadMain() { while (decoder_running_) { // Wait for a kick from WriteRegister. - decoder_fence_.Wait(); + //decoder_fence_.Wait(); // Check to see if we're supposed to exit if (!decoder_running_) { diff --git a/src/xenia/cpu/module.cc b/src/xenia/cpu/module.cc index d7fb2abde..8bf30e68d 100644 --- a/src/xenia/cpu/module.cc +++ b/src/xenia/cpu/module.cc @@ -149,7 +149,6 @@ SymbolStatus Module::DefineVariable(VariableInfo* symbol_info) { } void Module::ForEachFunction(std::function callback) { - SCOPE_profile_cpu_f("cpu"); std::lock_guard guard(lock_); for (auto& symbol_info : list_) { if (symbol_info->type() == SymbolType::kFunction) { @@ -159,21 +158,22 @@ void Module::ForEachFunction(std::function callback) { } } -void Module::ForEachFunction(size_t since, size_t& version, - std::function callback) { - SCOPE_profile_cpu_f("cpu"); +void Module::ForEachSymbol(size_t start_index, size_t end_index, + std::function callback) { std::lock_guard guard(lock_); - size_t count = list_.size(); - version = count; - for (size_t n = since; n < count; n++) { - auto& symbol_info = list_[n]; - if (symbol_info->type() == SymbolType::kFunction) { - FunctionInfo* info = static_cast(symbol_info.get()); - callback(info); - } + start_index = std::min(start_index, list_.size()); + end_index = std::min(end_index, list_.size()); + for (size_t i = start_index; i <= end_index; ++i) { + auto& symbol_info = list_[i]; + callback(symbol_info.get()); } } +size_t Module::QuerySymbolCount() { + std::lock_guard guard(lock_); + return list_.size(); +} + bool Module::ReadMap(const char* file_name) { std::ifstream infile(file_name); diff --git a/src/xenia/cpu/module.h b/src/xenia/cpu/module.h index 555585fcf..517c59557 100644 --- a/src/xenia/cpu/module.h +++ b/src/xenia/cpu/module.h @@ -47,8 +47,9 @@ class Module { SymbolStatus DefineVariable(VariableInfo* symbol_info); void ForEachFunction(std::function callback); - void ForEachFunction(size_t since, size_t& version, - std::function callback); + void ForEachSymbol(size_t start_index, size_t end_index, + std::function callback); + size_t QuerySymbolCount(); bool ReadMap(const char* file_name); diff --git a/src/xenia/debug/debugger.cc b/src/xenia/debug/debugger.cc index 90fc69724..b5ca19770 100644 --- a/src/xenia/debug/debugger.cc +++ b/src/xenia/debug/debugger.cc @@ -22,6 +22,9 @@ #include "xenia/cpu/function.h" #include "xenia/cpu/processor.h" #include "xenia/emulator.h" +#include "xenia/kernel/objects/xkernel_module.h" +#include "xenia/kernel/objects/xmodule.h" +#include "xenia/kernel/objects/xuser_module.h" // Autogenerated Flatbuffers files: #include "xenia/debug/proto/breakpoints_generated.h" @@ -39,6 +42,8 @@ DEFINE_bool(exit_with_debugger, true, "Exit whe the debugger disconnects."); namespace xe { namespace debug { +using namespace xe::kernel; + using xe::cpu::ThreadState; Breakpoint::Breakpoint(Type type, uint32_t address) @@ -69,7 +74,7 @@ bool Debugger::StartSession() { functions_trace_path_ = xe::join_paths(session_path, L"functions.trace"); functions_trace_file_ = ChunkedMappedMemoryWriter::Open( - functions_trace_path_, 32 * 1024 * 1024, true); + functions_trace_path_, 32 * 1024 * 1024, true); listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket_ < 1) { @@ -235,14 +240,149 @@ void Debugger::OnMessage(std::vector buffer) { case proto::RequestData_ListModulesRequest: { response_data_type = proto::ResponseData_ListModulesResponse; + auto modules = + emulator()->kernel_state()->object_table()->GetObjectsByType( + XObject::kTypeModule); + std::vector module_entries; + for (size_t i = 0; i < modules.size(); ++i) { + auto& module = modules[i]; + auto processor_module = module->processor_module(); + module_entries.emplace_back( + module->handle(), + processor_module ? uint32_t(processor_module->QuerySymbolCount()) + : 0); + } + auto module_entries_offset = + fbb.CreateVectorOfStructs(module_entries); auto response_data = proto::ListModulesResponseBuilder(fbb); - // + response_data.add_entry(module_entries_offset); response_data_offset = response_data.Finish().Union(); } break; case proto::RequestData_GetModuleRequest: { + auto request_data = reinterpret_cast( + request->request_data()); + auto module = + emulator()->kernel_state()->object_table()->LookupObject( + request_data->module_id()); + flatbuffers::Offset module_offset; + if (module) { + proto::XObject xobject_data(module->handle()); + auto module_name_offset = fbb.CreateString(module->name()); + auto module_path_offset = fbb.CreateString(module->path()); + proto::ModuleBuilder module_builder(fbb); + module_builder.add_object(&xobject_data); + module_builder.add_type( + static_cast(module->module_type())); + module_builder.add_name(module_name_offset); + module_builder.add_path(module_path_offset); + switch (module->module_type()) { + case XModule::ModuleType::kKernelModule: { + auto kernel_module = reinterpret_cast(module.get()); + break; + } + case XModule::ModuleType::kUserModule: { + auto user_module = reinterpret_cast(module.get()); + // user_module->xex? + break; + } + default: + assert_unhandled_case(module->module_type()); + break; + } + module_offset = module_builder.Finish(); + } response_data_type = proto::ResponseData_GetModuleResponse; auto response_data = proto::GetModuleResponseBuilder(fbb); - // + response_data.add_module(module_offset); + response_data_offset = response_data.Finish().Union(); + } break; + case proto::RequestData_ListFunctionsRequest: { + auto request_data = reinterpret_cast( + request->request_data()); + auto module = + emulator()->kernel_state()->object_table()->LookupObject( + request_data->module_id()); + if (!module || !module->processor_module()) { + response_data_type = proto::ResponseData_ListFunctionsResponse; + auto response_data = proto::ListFunctionsResponseBuilder(fbb); + response_data_offset = response_data.Finish().Union(); + break; + } + auto processor_module = module->processor_module(); + size_t max_function_count = request_data->function_index_end() - + request_data->function_index_start() + 1; + std::vector> function_list; + function_list.reserve(max_function_count); + processor_module->ForEachSymbol(request_data->function_index_start(), + request_data->function_index_end(), + [&](xe::cpu::SymbolInfo* symbol_info) { + if (symbol_info->type() != xe::cpu::SymbolType::kFunction) { + return; + } + auto function_info = + reinterpret_cast(symbol_info); + flatbuffers::Offset name_offset; + if (!function_info->name().empty()) { + name_offset = fbb.CreateString(function_info->name()); + } + auto function_entry = proto::FunctionEntryBuilder(fbb); + function_entry.add_identifier( + reinterpret_cast(function_info)); + function_entry.add_address_start(function_info->address()); + function_entry.add_address_end(function_info->end_address()); + function_entry.add_name(name_offset); + function_list.push_back(function_entry.Finish()); + }); + auto function_list_data = fbb.CreateVector(function_list); + response_data_type = proto::ResponseData_ListFunctionsResponse; + auto response_data = proto::ListFunctionsResponseBuilder(fbb); + response_data.add_entry(function_list_data); + response_data_offset = response_data.Finish().Union(); + } break; + case proto::RequestData_GetFunctionRequest: { + auto request_data = reinterpret_cast( + request->request_data()); + auto function_info = + reinterpret_cast(request_data->identifier()); + auto function = function_info->function(); + flatbuffers::Offset name_offset; + if (!function_info->name().empty()) { + name_offset = fbb.CreateString(function_info->name()); + } + flatbuffers::Offset disasm_ppc_offset; + flatbuffers::Offset disasm_hir_raw_offset; + flatbuffers::Offset disasm_hir_opt_offset; + flatbuffers::Offset disasm_machine_code_offset; + if (function && function->debug_info()) { + auto debug_info = function->debug_info(); + if (debug_info->source_disasm()) { + disasm_ppc_offset = fbb.CreateString(debug_info->source_disasm()); + } + if (debug_info->raw_hir_disasm()) { + disasm_hir_raw_offset = + fbb.CreateString(debug_info->raw_hir_disasm()); + } + if (debug_info->hir_disasm()) { + disasm_hir_opt_offset = fbb.CreateString(debug_info->hir_disasm()); + } + if (debug_info->machine_code_disasm()) { + disasm_machine_code_offset = + fbb.CreateString(debug_info->machine_code_disasm()); + } + } + auto function_data = proto::FunctionBuilder(fbb); + function_data.add_identifier(request_data->identifier()); + function_data.add_address_start(function_info->address()); + function_data.add_address_end(function_info->end_address()); + function_data.add_name(name_offset); + function_data.add_disasm_ppc(disasm_ppc_offset); + function_data.add_disasm_hir_raw(disasm_hir_raw_offset); + function_data.add_disasm_hir_opt(disasm_hir_opt_offset); + function_data.add_disasm_machine_code(disasm_machine_code_offset); + auto function_offset = function_data.Finish(); + response_data_type = proto::ResponseData_GetFunctionResponse; + auto response_data = proto::GetFunctionResponseBuilder(fbb); + response_data.add_function(function_offset); response_data_offset = response_data.Finish().Union(); } break; diff --git a/src/xenia/debug/proto/messages.fbs b/src/xenia/debug/proto/messages.fbs index 48a2cdaf2..9c3017915 100644 --- a/src/xenia/debug/proto/messages.fbs +++ b/src/xenia/debug/proto/messages.fbs @@ -25,6 +25,8 @@ union RequestData { ListModulesRequest, GetModuleRequest, + ListFunctionsRequest, + GetFunctionRequest, StopRequest, BreakRequest, @@ -47,6 +49,8 @@ union ResponseData { ListModulesResponse, GetModuleResponse, + ListFunctionsResponse, + GetFunctionResponse, StopResponse, BreakResponse, diff --git a/src/xenia/debug/proto/messages_generated.h b/src/xenia/debug/proto/messages_generated.h index 2efb31298..fad763993 100644 --- a/src/xenia/debug/proto/messages_generated.h +++ b/src/xenia/debug/proto/messages_generated.h @@ -48,9 +48,16 @@ namespace debug { namespace proto { struct Module; struct ListModulesRequest; +struct ListModuleEntry; struct ListModulesResponse; struct GetModuleRequest; struct GetModuleResponse; +struct FunctionEntry; +struct Function; +struct ListFunctionsRequest; +struct ListFunctionsResponse; +struct GetFunctionRequest; +struct GetFunctionResponse; } // namespace proto } // namespace debug } // namespace xe @@ -82,14 +89,24 @@ enum RequestData { RequestData_RemoveBreakpointsRequest = 5, RequestData_ListModulesRequest = 6, RequestData_GetModuleRequest = 7, - RequestData_StopRequest = 8, - RequestData_BreakRequest = 9, - RequestData_ContinueRequest = 10, - RequestData_StepRequest = 11 + RequestData_ListFunctionsRequest = 8, + RequestData_GetFunctionRequest = 9, + RequestData_StopRequest = 10, + RequestData_BreakRequest = 11, + RequestData_ContinueRequest = 12, + RequestData_StepRequest = 13 }; inline const char **EnumNamesRequestData() { - static const char *names[] = { "NONE", "AttachRequest", "ListBreakpointsRequest", "AddBreakpointsRequest", "UpdateBreakpointsRequest", "RemoveBreakpointsRequest", "ListModulesRequest", "GetModuleRequest", "StopRequest", "BreakRequest", "ContinueRequest", "StepRequest", nullptr }; + static const char *names[] = { + "NONE", "AttachRequest", + "ListBreakpointsRequest", "AddBreakpointsRequest", + "UpdateBreakpointsRequest", "RemoveBreakpointsRequest", + "ListModulesRequest", "GetModuleRequest", + "ListFunctionsRequest", "GetFunctionRequest", + "StopRequest", "BreakRequest", + "ContinueRequest", "StepRequest", + nullptr}; return names; } @@ -106,16 +123,27 @@ enum ResponseData { ResponseData_RemoveBreakpointsResponse = 5, ResponseData_ListModulesResponse = 6, ResponseData_GetModuleResponse = 7, - ResponseData_StopResponse = 8, - ResponseData_BreakResponse = 9, - ResponseData_ContinueResponse = 10, - ResponseData_StepResponse = 11, - ResponseData_BreakpointEvent = 12, - ResponseData_AccessViolationEvent = 13 + ResponseData_ListFunctionsResponse = 8, + ResponseData_GetFunctionResponse = 9, + ResponseData_StopResponse = 10, + ResponseData_BreakResponse = 11, + ResponseData_ContinueResponse = 12, + ResponseData_StepResponse = 13, + ResponseData_BreakpointEvent = 14, + ResponseData_AccessViolationEvent = 15 }; inline const char **EnumNamesResponseData() { - static const char *names[] = { "NONE", "AttachResponse", "ListBreakpointsResponse", "AddBreakpointsResponse", "UpdateBreakpointsResponse", "RemoveBreakpointsResponse", "ListModulesResponse", "GetModuleResponse", "StopResponse", "BreakResponse", "ContinueResponse", "StepResponse", "BreakpointEvent", "AccessViolationEvent", nullptr }; + static const char *names[] = { + "NONE", "AttachResponse", + "ListBreakpointsResponse", "AddBreakpointsResponse", + "UpdateBreakpointsResponse", "RemoveBreakpointsResponse", + "ListModulesResponse", "GetModuleResponse", + "ListFunctionsResponse", "GetFunctionResponse", + "StopResponse", "BreakResponse", + "ContinueResponse", "StepResponse", + "BreakpointEvent", "AccessViolationEvent", + nullptr}; return names; } @@ -275,6 +303,14 @@ inline bool VerifyRequestData(flatbuffers::Verifier &verifier, const void *union case RequestData_RemoveBreakpointsRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); case RequestData_ListModulesRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); case RequestData_GetModuleRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); + case RequestData_ListFunctionsRequest: + return verifier.VerifyTable( + reinterpret_cast( + union_obj)); + case RequestData_GetFunctionRequest: + return verifier.VerifyTable( + reinterpret_cast( + union_obj)); case RequestData_StopRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); case RequestData_BreakRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); case RequestData_ContinueRequest: return verifier.VerifyTable(reinterpret_cast(union_obj)); @@ -293,6 +329,14 @@ inline bool VerifyResponseData(flatbuffers::Verifier &verifier, const void *unio case ResponseData_RemoveBreakpointsResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); case ResponseData_ListModulesResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); case ResponseData_GetModuleResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); + case ResponseData_ListFunctionsResponse: + return verifier.VerifyTable( + reinterpret_cast( + union_obj)); + case ResponseData_GetFunctionResponse: + return verifier.VerifyTable( + reinterpret_cast( + union_obj)); case ResponseData_StopResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); case ResponseData_BreakResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); case ResponseData_ContinueResponse: return verifier.VerifyTable(reinterpret_cast(union_obj)); diff --git a/src/xenia/debug/proto/modules.fbs b/src/xenia/debug/proto/modules.fbs index 8f30ce1ad..b41271f54 100644 --- a/src/xenia/debug/proto/modules.fbs +++ b/src/xenia/debug/proto/modules.fbs @@ -3,8 +3,8 @@ include "common.fbs"; namespace xe.debug.proto; enum ModuleType:byte { - Kernel, - User, + Kernel = 0, + User = 1, } table Module { @@ -18,8 +18,12 @@ table Module { table ListModulesRequest { } +struct ListModuleEntry { + handle:uint; + function_count:uint; +} table ListModulesResponse { - module_ids:[uint]; + entry:[ListModuleEntry]; } table GetModuleRequest { @@ -29,3 +33,36 @@ table GetModuleResponse { module:Module; } +table FunctionEntry { + identifier:ulong; + address_start:uint; + address_end:uint; + name:string; +} +table Function { + identifier:ulong; + address_start:uint; + address_end:uint; + name:string; + + disasm_ppc:string; + disasm_hir_raw:string; + disasm_hir_opt:string; + disasm_machine_code:string; +} + +table ListFunctionsRequest { + module_id:uint; + function_index_start:uint; + function_index_end:uint; +} +table ListFunctionsResponse { + entry:[FunctionEntry]; +} + +table GetFunctionRequest { + identifier:ulong; +} +table GetFunctionResponse { + function:Function; +} diff --git a/src/xenia/debug/proto/modules_generated.h b/src/xenia/debug/proto/modules_generated.h index 23d221130..6ca094f3f 100644 --- a/src/xenia/debug/proto/modules_generated.h +++ b/src/xenia/debug/proto/modules_generated.h @@ -19,9 +19,16 @@ namespace proto { struct Module; struct ListModulesRequest; +struct ListModuleEntry; struct ListModulesResponse; struct GetModuleRequest; struct GetModuleResponse; +struct FunctionEntry; +struct Function; +struct ListFunctionsRequest; +struct ListFunctionsResponse; +struct GetFunctionRequest; +struct GetFunctionResponse; enum ModuleType { ModuleType_Kernel = 0, @@ -35,6 +42,23 @@ inline const char **EnumNamesModuleType() { inline const char *EnumNameModuleType(ModuleType e) { return EnumNamesModuleType()[e]; } +MANUALLY_ALIGNED_STRUCT(4) ListModuleEntry FLATBUFFERS_FINAL_CLASS { + private: + uint32_t handle_; + uint32_t function_count_; + + public: + ListModuleEntry(uint32_t handle, uint32_t function_count) + : handle_(flatbuffers::EndianScalar(handle)), + function_count_(flatbuffers::EndianScalar(function_count)) {} + + uint32_t handle() const { return flatbuffers::EndianScalar(handle_); } + uint32_t function_count() const { + return flatbuffers::EndianScalar(function_count_); + } +}; +STRUCT_END(ListModuleEntry, 8); + struct Module FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const xe::debug::proto::XObject *object() const { return GetStruct(4); } ModuleType type() const { return static_cast(GetField(6, 0)); } @@ -104,19 +128,23 @@ inline flatbuffers::Offset CreateListModulesRequest(flatbuff } struct ListModulesResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - const flatbuffers::Vector *module_ids() const { return GetPointer *>(4); } + const flatbuffers::Vector *entry() const { + return GetPointer *>(4); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* module_ids */) && - verifier.Verify(module_ids()) && - verifier.EndTable(); + VerifyField(verifier, 4 /* entry */) && + verifier.Verify(entry()) && verifier.EndTable(); } }; struct ListModulesResponseBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_module_ids(flatbuffers::Offset> module_ids) { fbb_.AddOffset(4, module_ids); } + void add_entry( + flatbuffers::Offset> entry) { + fbb_.AddOffset(4, entry); + } ListModulesResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } ListModulesResponseBuilder &operator=(const ListModulesResponseBuilder &); flatbuffers::Offset Finish() { @@ -125,10 +153,12 @@ struct ListModulesResponseBuilder { } }; -inline flatbuffers::Offset CreateListModulesResponse(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset> module_ids = 0) { +inline flatbuffers::Offset CreateListModulesResponse( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> entry = + 0) { ListModulesResponseBuilder builder_(_fbb); - builder_.add_module_ids(module_ids); + builder_.add_entry(entry); return builder_.Finish(); } @@ -189,6 +219,317 @@ inline flatbuffers::Offset CreateGetModuleResponse(flatbuffer return builder_.Finish(); } +struct FunctionEntry FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + uint64_t identifier() const { return GetField(4, 0); } + uint32_t address_start() const { return GetField(6, 0); } + uint32_t address_end() const { return GetField(8, 0); } + const flatbuffers::String *name() const { + return GetPointer(10); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* identifier */) && + VerifyField(verifier, 6 /* address_start */) && + VerifyField(verifier, 8 /* address_end */) && + VerifyField(verifier, 10 /* name */) && + verifier.Verify(name()) && verifier.EndTable(); + } +}; + +struct FunctionEntryBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_identifier(uint64_t identifier) { + fbb_.AddElement(4, identifier, 0); + } + void add_address_start(uint32_t address_start) { + fbb_.AddElement(6, address_start, 0); + } + void add_address_end(uint32_t address_end) { + fbb_.AddElement(8, address_end, 0); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(10, name); + } + FunctionEntryBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + FunctionEntryBuilder &operator=(const FunctionEntryBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 4)); + return o; + } +}; + +inline flatbuffers::Offset CreateFunctionEntry( + flatbuffers::FlatBufferBuilder &_fbb, uint64_t identifier = 0, + uint32_t address_start = 0, uint32_t address_end = 0, + flatbuffers::Offset name = 0) { + FunctionEntryBuilder builder_(_fbb); + builder_.add_identifier(identifier); + builder_.add_name(name); + builder_.add_address_end(address_end); + builder_.add_address_start(address_start); + return builder_.Finish(); +} + +struct Function FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + uint64_t identifier() const { return GetField(4, 0); } + uint32_t address_start() const { return GetField(6, 0); } + uint32_t address_end() const { return GetField(8, 0); } + const flatbuffers::String *name() const { + return GetPointer(10); + } + const flatbuffers::String *disasm_ppc() const { + return GetPointer(12); + } + const flatbuffers::String *disasm_hir_raw() const { + return GetPointer(14); + } + const flatbuffers::String *disasm_hir_opt() const { + return GetPointer(16); + } + const flatbuffers::String *disasm_machine_code() const { + return GetPointer(18); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* identifier */) && + VerifyField(verifier, 6 /* address_start */) && + VerifyField(verifier, 8 /* address_end */) && + VerifyField(verifier, 10 /* name */) && + verifier.Verify(name()) && + VerifyField(verifier, 12 /* disasm_ppc */) && + verifier.Verify(disasm_ppc()) && + VerifyField(verifier, + 14 /* disasm_hir_raw */) && + verifier.Verify(disasm_hir_raw()) && + VerifyField(verifier, + 16 /* disasm_hir_opt */) && + verifier.Verify(disasm_hir_opt()) && + VerifyField(verifier, + 18 /* disasm_machine_code */) && + verifier.Verify(disasm_machine_code()) && verifier.EndTable(); + } +}; + +struct FunctionBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_identifier(uint64_t identifier) { + fbb_.AddElement(4, identifier, 0); + } + void add_address_start(uint32_t address_start) { + fbb_.AddElement(6, address_start, 0); + } + void add_address_end(uint32_t address_end) { + fbb_.AddElement(8, address_end, 0); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(10, name); + } + void add_disasm_ppc(flatbuffers::Offset disasm_ppc) { + fbb_.AddOffset(12, disasm_ppc); + } + void add_disasm_hir_raw( + flatbuffers::Offset disasm_hir_raw) { + fbb_.AddOffset(14, disasm_hir_raw); + } + void add_disasm_hir_opt( + flatbuffers::Offset disasm_hir_opt) { + fbb_.AddOffset(16, disasm_hir_opt); + } + void add_disasm_machine_code( + flatbuffers::Offset disasm_machine_code) { + fbb_.AddOffset(18, disasm_machine_code); + } + FunctionBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + FunctionBuilder &operator=(const FunctionBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 8)); + return o; + } +}; + +inline flatbuffers::Offset CreateFunction( + flatbuffers::FlatBufferBuilder &_fbb, uint64_t identifier = 0, + uint32_t address_start = 0, uint32_t address_end = 0, + flatbuffers::Offset name = 0, + flatbuffers::Offset disasm_ppc = 0, + flatbuffers::Offset disasm_hir_raw = 0, + flatbuffers::Offset disasm_hir_opt = 0, + flatbuffers::Offset disasm_machine_code = 0) { + FunctionBuilder builder_(_fbb); + builder_.add_identifier(identifier); + builder_.add_disasm_machine_code(disasm_machine_code); + builder_.add_disasm_hir_opt(disasm_hir_opt); + builder_.add_disasm_hir_raw(disasm_hir_raw); + builder_.add_disasm_ppc(disasm_ppc); + builder_.add_name(name); + builder_.add_address_end(address_end); + builder_.add_address_start(address_start); + return builder_.Finish(); +} + +struct ListFunctionsRequest FLATBUFFERS_FINAL_CLASS + : private flatbuffers::Table { + uint32_t module_id() const { return GetField(4, 0); } + uint32_t function_index_start() const { return GetField(6, 0); } + uint32_t function_index_end() const { return GetField(8, 0); } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* module_id */) && + VerifyField(verifier, 6 /* function_index_start */) && + VerifyField(verifier, 8 /* function_index_end */) && + verifier.EndTable(); + } +}; + +struct ListFunctionsRequestBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_module_id(uint32_t module_id) { + fbb_.AddElement(4, module_id, 0); + } + void add_function_index_start(uint32_t function_index_start) { + fbb_.AddElement(6, function_index_start, 0); + } + void add_function_index_end(uint32_t function_index_end) { + fbb_.AddElement(8, function_index_end, 0); + } + ListFunctionsRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ListFunctionsRequestBuilder &operator=(const ListFunctionsRequestBuilder &); + flatbuffers::Offset Finish() { + auto o = + flatbuffers::Offset(fbb_.EndTable(start_, 3)); + return o; + } +}; + +inline flatbuffers::Offset CreateListFunctionsRequest( + flatbuffers::FlatBufferBuilder &_fbb, uint32_t module_id = 0, + uint32_t function_index_start = 0, uint32_t function_index_end = 0) { + ListFunctionsRequestBuilder builder_(_fbb); + builder_.add_function_index_end(function_index_end); + builder_.add_function_index_start(function_index_start); + builder_.add_module_id(module_id); + return builder_.Finish(); +} + +struct ListFunctionsResponse FLATBUFFERS_FINAL_CLASS + : private flatbuffers::Table { + const flatbuffers::Vector> *entry() const { + return GetPointer< + const flatbuffers::Vector> *>(4); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* entry */) && + verifier.Verify(entry()) && verifier.VerifyVectorOfTables(entry()) && + verifier.EndTable(); + } +}; + +struct ListFunctionsResponseBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_entry(flatbuffers::Offset< + flatbuffers::Vector>> entry) { + fbb_.AddOffset(4, entry); + } + ListFunctionsResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ListFunctionsResponseBuilder &operator=(const ListFunctionsResponseBuilder &); + flatbuffers::Offset Finish() { + auto o = + flatbuffers::Offset(fbb_.EndTable(start_, 1)); + return o; + } +}; + +inline flatbuffers::Offset CreateListFunctionsResponse( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> + entry = 0) { + ListFunctionsResponseBuilder builder_(_fbb); + builder_.add_entry(entry); + return builder_.Finish(); +} + +struct GetFunctionRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + uint64_t identifier() const { return GetField(4, 0); } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* identifier */) && + verifier.EndTable(); + } +}; + +struct GetFunctionRequestBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_identifier(uint64_t identifier) { + fbb_.AddElement(4, identifier, 0); + } + GetFunctionRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + GetFunctionRequestBuilder &operator=(const GetFunctionRequestBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 1)); + return o; + } +}; + +inline flatbuffers::Offset CreateGetFunctionRequest( + flatbuffers::FlatBufferBuilder &_fbb, uint64_t identifier = 0) { + GetFunctionRequestBuilder builder_(_fbb); + builder_.add_identifier(identifier); + return builder_.Finish(); +} + +struct GetFunctionResponse FLATBUFFERS_FINAL_CLASS + : private flatbuffers::Table { + const Function *function() const { return GetPointer(4); } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* function */) && + verifier.VerifyTable(function()) && verifier.EndTable(); + } +}; + +struct GetFunctionResponseBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_function(flatbuffers::Offset function) { + fbb_.AddOffset(4, function); + } + GetFunctionResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + GetFunctionResponseBuilder &operator=(const GetFunctionResponseBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 1)); + return o; + } +}; + +inline flatbuffers::Offset CreateGetFunctionResponse( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset function = 0) { + GetFunctionResponseBuilder builder_(_fbb); + builder_.add_function(function); + return builder_.Finish(); +} + } // namespace proto } // namespace debug } // namespace xe diff --git a/src/xenia/kernel/objects/xkernel_module.cc b/src/xenia/kernel/objects/xkernel_module.cc index 8093e0346..9f714ebf9 100644 --- a/src/xenia/kernel/objects/xkernel_module.cc +++ b/src/xenia/kernel/objects/xkernel_module.cc @@ -18,7 +18,7 @@ namespace xe { namespace kernel { XKernelModule::XKernelModule(KernelState* kernel_state, const char* path) - : XModule(kernel_state, path) { + : XModule(kernel_state, ModuleType::kKernelModule, path) { emulator_ = kernel_state->emulator(); memory_ = emulator_->memory(); export_resolver_ = kernel_state->emulator()->export_resolver(); diff --git a/src/xenia/kernel/objects/xmodule.cc b/src/xenia/kernel/objects/xmodule.cc index a4505ab82..db2dd1e87 100644 --- a/src/xenia/kernel/objects/xmodule.cc +++ b/src/xenia/kernel/objects/xmodule.cc @@ -15,8 +15,12 @@ namespace xe { namespace kernel { -XModule::XModule(KernelState* kernel_state, const std::string& path) - : XObject(kernel_state, kTypeModule), path_(path) { +XModule::XModule(KernelState* kernel_state, ModuleType module_type, + const std::string& path) + : XObject(kernel_state, kTypeModule), + module_type_(module_type), + path_(path), + processor_module_(nullptr) { auto last_slash = path.find_last_of('/'); if (last_slash == path.npos) { last_slash = path.find_last_of('\\'); diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index 123ace447..5c62c2d50 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -12,6 +12,7 @@ #include +#include "xenia/cpu/module.h" #include "xenia/kernel/xobject.h" #include "xenia/xbox.h" @@ -20,13 +21,23 @@ namespace kernel { class XModule : public XObject { public: - XModule(KernelState* kernel_state, const std::string& path); + enum class ModuleType { + // Matches debugger Module type. + kKernelModule = 0, + kUserModule = 1, + }; + + XModule(KernelState* kernel_state, ModuleType module_type, + const std::string& path); virtual ~XModule(); + ModuleType module_type() const { return module_type_; } const std::string& path() const { return path_; } const std::string& name() const { return name_; } bool Matches(const std::string& name) const; + xe::cpu::Module* processor_module() const { return processor_module_; } + virtual uint32_t GetProcAddressByOrdinal(uint16_t ordinal) = 0; virtual uint32_t GetProcAddressByName(const char* name) = 0; virtual X_STATUS GetSection(const char* name, uint32_t* out_section_data, @@ -35,8 +46,11 @@ class XModule : public XObject { protected: void OnLoad(); + ModuleType module_type_; std::string name_; std::string path_; + + xe::cpu::Module* processor_module_; }; } // namespace kernel diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 907069b81..830729aaa 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -21,7 +21,9 @@ namespace kernel { using namespace xe::cpu; XUserModule::XUserModule(KernelState* kernel_state, const char* path) - : XModule(kernel_state, path), xex_(nullptr), execution_info_ptr_(0) {} + : XModule(kernel_state, ModuleType::kUserModule, path), + xex_(nullptr), + execution_info_ptr_(0) {} XUserModule::~XUserModule() { kernel_state()->memory()->SystemHeapFree(execution_info_ptr_); @@ -119,6 +121,7 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) { if (!xex_module->Load(name_, path_, xex_)) { return X_STATUS_UNSUCCESSFUL; } + processor_module_ = xex_module.get(); if (!processor->AddModule(std::move(xex_module))) { return X_STATUS_UNSUCCESSFUL; }