diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 35014cebf..d0d127d95 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -2,6 +2,7 @@ Process Hacker 1.3.6.6 * NEW: + * Proper symbol support with dbghelp.dll * Aggressive mode (start with "-a" command line option) * FIXED: * Service properties Key handle leak diff --git a/trunk/ProcessHacker/Components/ThreadList.cs b/trunk/ProcessHacker/Components/ThreadList.cs index a87ba5a4d..99f181495 100644 --- a/trunk/ProcessHacker/Components/ThreadList.cs +++ b/trunk/ProcessHacker/Components/ThreadList.cs @@ -87,6 +87,8 @@ namespace ProcessHacker private void listThreads_SelectedIndexChanged(object sender, System.EventArgs e) { + this.Cursor = Cursors.WaitCursor; + if (listThreads.SelectedItems.Count == 1) { try @@ -94,9 +96,18 @@ namespace ProcessHacker int tid = int.Parse(listThreads.SelectedItems[0].Name); ProcessItem process = Program.HackerWindow.ProcessProvider.Dictionary[_pid]; ProcessThread thread = Misc.GetThreadById(Process.GetProcessById(_pid), tid); + string fileName; - fileModule.Text = _provider.Symbols.GetModuleFromAddress(_provider.Dictionary[tid].StartAddressI); - fileModule.Enabled = true; + try + { + _provider.Symbols.GetSymbolFromAddress(_provider.Dictionary[tid].StartAddressI, out fileName); + fileModule.Text = fileName; + fileModule.Enabled = true; + } + catch + { + fileModule.Enabled = false; + } if (thread.ThreadState == ThreadState.Wait) { @@ -136,6 +147,8 @@ namespace ProcessHacker if (this.SelectedIndexChanged != null) this.SelectedIndexChanged(sender, e); + + this.Cursor = Cursors.Default; } private void ThreadList_KeyDown(object sender, KeyEventArgs e) @@ -201,6 +214,7 @@ namespace ProcessHacker _provider.DictionaryModified -= new ThreadProvider.ProviderDictionaryModified(provider_DictionaryModified); _provider.DictionaryRemoved -= new ThreadProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); _provider.Updated -= new ThreadProvider.ProviderUpdateOnce(provider_Updated); + _provider.LoadingStateChanged -= new ThreadProvider.LoadingStateChangedDelegate(provider_LoadingStateChanged); } _provider = value; @@ -220,6 +234,7 @@ namespace ProcessHacker _provider.DictionaryModified += new ThreadProvider.ProviderDictionaryModified(provider_DictionaryModified); _provider.DictionaryRemoved += new ThreadProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); _provider.Updated += new ThreadProvider.ProviderUpdateOnce(provider_Updated); + _provider.LoadingStateChanged += new ThreadProvider.LoadingStateChangedDelegate(provider_LoadingStateChanged); _pid = _provider.PID; _process = Process.GetProcessById(_pid); @@ -326,6 +341,17 @@ namespace ProcessHacker listThreads.Items[item.TID.ToString()].Remove(); } + private void provider_LoadingStateChanged(bool loading) + { + this.BeginInvoke(new MethodInvoker(delegate + { + if (loading) + listThreads.Cursor = Cursors.AppStarting; + else + listThreads.Cursor = Cursors.Default; + })); + } + public void SaveSettings() { Properties.Settings.Default.ThreadListViewColumns = ColumnSettings.SaveSettings(listThreads); @@ -468,23 +494,13 @@ namespace ProcessHacker return; } - ThreadWindow window; - try { - window = Program.GetThreadWindow(_pid, - Int32.Parse(listThreads.SelectedItems[0].SubItems[0].Text), - _provider.Symbols, - new Program.ThreadWindowInvokeAction(delegate(ThreadWindow f) - { - try - { - f.Show(); - f.Activate(); - } - catch - { } - })); + (new ThreadWindow( + _pid, + Int32.Parse(listThreads.SelectedItems[0].SubItems[0].Text), + _provider.Symbols) + ).ShowDialog(this); } catch { } diff --git a/trunk/ProcessHacker/Forms/HackerWindow.cs b/trunk/ProcessHacker/Forms/HackerWindow.cs index 52d1baf3b..5a32f0ea1 100644 --- a/trunk/ProcessHacker/Forms/HackerWindow.cs +++ b/trunk/ProcessHacker/Forms/HackerWindow.cs @@ -216,6 +216,11 @@ namespace ProcessHacker }, this.Handle); } + private void apiLoggerMenuItem_Click(object sender, EventArgs e) + { + (new Forms.ApiLogWindow()).Show(); + } + private void findHandlesMenuItem_Click(object sender, EventArgs e) { if (HandleFilterWindow == null) @@ -1851,6 +1856,8 @@ namespace ProcessHacker HistoryManager.GlobalMaxCount = Properties.Settings.Default.MaxSamples; ProcessHacker.Components.Plotter.GlobalMoveStep = Properties.Settings.Default.PlotterStep; + + Win32.LoadLibrary(Properties.Settings.Default.DbgHelpPath); } public void QueueMessage(string message) @@ -2227,35 +2234,6 @@ namespace ProcessHacker }; } - private void LoadSymbols() - { - ThreadPool.QueueUserWorkItem(new WaitCallback(o => - { - try - { - string[] modules = - { - "advapi32.dll", "comctl32.dll", "crypt32.dll", "dnsapi.dll", - "gdi32.dll", "imagehlp.dll", "kernel32.dll", - "ntdll.dll", "ole32.dll", "psapi.dll", "rpcrt4.dll", "shell32.dll", - "user32.dll", "winsta.dll", "wintrust.dll", "wtsapi32.dll" }; - - foreach (string module in modules) - { - try - { - SymbolProvider.BaseInstance.LoadSymbolsFromLibrary(Environment.SystemDirectory + "\\" + module, - (uint)Win32.GetModuleHandle(module)); - } - catch - { } - } - } - catch - { } - })); - } - private void LoadApplyCommandLineArgs() { tabControl.SelectedTab = tabControl.TabPages["tab" + Program.SelectTab]; @@ -2292,7 +2270,6 @@ namespace ProcessHacker this.LoadSettings(); this.LoadControls(); this.LoadAddShortcuts(); - this.LoadSymbols(); this.ResumeLayout(); if ((!Properties.Settings.Default.StartHidden && !Program.StartHidden) || @@ -2368,10 +2345,5 @@ namespace ProcessHacker } base.OnResize(e); } - - private void apiLoggerMenuItem_Click(object sender, EventArgs e) - { - (new Forms.ApiLogWindow()).Show(); - } } } diff --git a/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs b/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs index 6a4c3c2da..ebb57fbf8 100644 --- a/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs @@ -59,6 +59,8 @@ this.checkHideHandlesWithNoName = new System.Windows.Forms.CheckBox(); this.checkVerifySignatures = new System.Windows.Forms.CheckBox(); this.tabHighlighting = new System.Windows.Forms.TabPage(); + this.buttonDisableAll = new System.Windows.Forms.Button(); + this.buttonEnableAll = new System.Windows.Forms.Button(); this.label5 = new System.Windows.Forms.Label(); this.listHighlightingColors = new System.Windows.Forms.ListView(); this.columnDescription = new System.Windows.Forms.ColumnHeader(); @@ -84,11 +86,16 @@ this.colorMemoryPB = new ProcessHacker.Components.ColorModifier(); this.colorCPUUT = new ProcessHacker.Components.ColorModifier(); this.colorCPUKT = new ProcessHacker.Components.ColorModifier(); + this.tabSymbols = new System.Windows.Forms.TabPage(); + this.checkUndecorate = new System.Windows.Forms.CheckBox(); + this.textSearchPath = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.buttonDbghelpBrowse = new System.Windows.Forms.Button(); + this.textDbghelpPath = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); this.label22 = new System.Windows.Forms.Label(); this.toolTipProvider = new System.Windows.Forms.ToolTip(this.components); this.buttonCancel = new System.Windows.Forms.Button(); - this.buttonEnableAll = new System.Windows.Forms.Button(); - this.buttonDisableAll = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.textUpdateInterval)).BeginInit(); this.tabControl.SuspendLayout(); this.tabGeneral.SuspendLayout(); @@ -99,6 +106,7 @@ ((System.ComponentModel.ISupportInitialize)(this.textHighlightingDuration)).BeginInit(); this.tabPlotting.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.textStep)).BeginInit(); + this.tabSymbols.SuspendLayout(); this.SuspendLayout(); // // label1 @@ -207,6 +215,7 @@ this.tabControl.Controls.Add(this.tabAdvanced); this.tabControl.Controls.Add(this.tabHighlighting); this.tabControl.Controls.Add(this.tabPlotting); + this.tabControl.Controls.Add(this.tabSymbols); this.tabControl.Location = new System.Drawing.Point(12, 12); this.tabControl.Name = "tabControl"; this.tabControl.SelectedIndex = 0; @@ -522,6 +531,30 @@ this.tabHighlighting.Text = "Highlighting"; this.tabHighlighting.UseVisualStyleBackColor = true; // + // buttonDisableAll + // + this.buttonDisableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDisableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDisableAll.Location = new System.Drawing.Point(336, 312); + this.buttonDisableAll.Name = "buttonDisableAll"; + this.buttonDisableAll.Size = new System.Drawing.Size(75, 23); + this.buttonDisableAll.TabIndex = 12; + this.buttonDisableAll.Text = "&Disable All"; + this.buttonDisableAll.UseVisualStyleBackColor = true; + this.buttonDisableAll.Click += new System.EventHandler(this.buttonDisableAll_Click); + // + // buttonEnableAll + // + this.buttonEnableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEnableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonEnableAll.Location = new System.Drawing.Point(255, 312); + this.buttonEnableAll.Name = "buttonEnableAll"; + this.buttonEnableAll.Size = new System.Drawing.Size(75, 23); + this.buttonEnableAll.TabIndex = 12; + this.buttonEnableAll.Text = "&Enable All"; + this.buttonEnableAll.UseVisualStyleBackColor = true; + this.buttonEnableAll.Click += new System.EventHandler(this.buttonEnableAll_Click); + // // label5 // this.label5.AutoSize = true; @@ -801,6 +834,84 @@ this.colorCPUKT.Size = new System.Drawing.Size(40, 20); this.colorCPUKT.TabIndex = 11; // + // tabSymbols + // + this.tabSymbols.Controls.Add(this.checkUndecorate); + this.tabSymbols.Controls.Add(this.textSearchPath); + this.tabSymbols.Controls.Add(this.label10); + this.tabSymbols.Controls.Add(this.buttonDbghelpBrowse); + this.tabSymbols.Controls.Add(this.textDbghelpPath); + this.tabSymbols.Controls.Add(this.label9); + this.tabSymbols.Location = new System.Drawing.Point(4, 22); + this.tabSymbols.Name = "tabSymbols"; + this.tabSymbols.Padding = new System.Windows.Forms.Padding(3); + this.tabSymbols.Size = new System.Drawing.Size(417, 341); + this.tabSymbols.TabIndex = 4; + this.tabSymbols.Text = "Symbols"; + this.tabSymbols.UseVisualStyleBackColor = true; + // + // checkUndecorate + // + this.checkUndecorate.AutoSize = true; + this.checkUndecorate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkUndecorate.Location = new System.Drawing.Point(6, 60); + this.checkUndecorate.Name = "checkUndecorate"; + this.checkUndecorate.Size = new System.Drawing.Size(128, 18); + this.checkUndecorate.TabIndex = 5; + this.checkUndecorate.Text = "Undecorate symbols"; + this.toolTipProvider.SetToolTip(this.checkUndecorate, "If selected, C++ symbol names will be undecorated."); + this.checkUndecorate.UseVisualStyleBackColor = true; + // + // textSearchPath + // + this.textSearchPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textSearchPath.Location = new System.Drawing.Point(99, 34); + this.textSearchPath.Name = "textSearchPath"; + this.textSearchPath.Size = new System.Drawing.Size(312, 20); + this.textSearchPath.TabIndex = 4; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(6, 37); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(68, 13); + this.label10.TabIndex = 3; + this.label10.Text = "Search path:"; + // + // buttonDbghelpBrowse + // + this.buttonDbghelpBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDbghelpBrowse.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDbghelpBrowse.Location = new System.Drawing.Point(336, 6); + this.buttonDbghelpBrowse.Name = "buttonDbghelpBrowse"; + this.buttonDbghelpBrowse.Size = new System.Drawing.Size(75, 23); + this.buttonDbghelpBrowse.TabIndex = 2; + this.buttonDbghelpBrowse.Text = "Browse..."; + this.buttonDbghelpBrowse.UseVisualStyleBackColor = true; + this.buttonDbghelpBrowse.Click += new System.EventHandler(this.buttonDbghelpBrowse_Click); + // + // textDbghelpPath + // + this.textDbghelpPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDbghelpPath.Location = new System.Drawing.Point(99, 8); + this.textDbghelpPath.Name = "textDbghelpPath"; + this.textDbghelpPath.Size = new System.Drawing.Size(231, 20); + this.textDbghelpPath.TabIndex = 1; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(6, 11); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(87, 13); + this.label9.TabIndex = 0; + this.label9.Text = "Dbghelp.dll path:"; + this.toolTipProvider.SetToolTip(this.label9, "Select the most recent version of dbghelp.dll available, usually distributed with" + + " Debugging Tools for Windows."); + // // label22 // this.label22.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -831,30 +942,6 @@ this.buttonCancel.UseVisualStyleBackColor = true; this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); // - // buttonEnableAll - // - this.buttonEnableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonEnableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonEnableAll.Location = new System.Drawing.Point(255, 312); - this.buttonEnableAll.Name = "buttonEnableAll"; - this.buttonEnableAll.Size = new System.Drawing.Size(75, 23); - this.buttonEnableAll.TabIndex = 12; - this.buttonEnableAll.Text = "&Enable All"; - this.buttonEnableAll.UseVisualStyleBackColor = true; - this.buttonEnableAll.Click += new System.EventHandler(this.buttonEnableAll_Click); - // - // buttonDisableAll - // - this.buttonDisableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonDisableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonDisableAll.Location = new System.Drawing.Point(336, 312); - this.buttonDisableAll.Name = "buttonDisableAll"; - this.buttonDisableAll.Size = new System.Drawing.Size(75, 23); - this.buttonDisableAll.TabIndex = 12; - this.buttonDisableAll.Text = "&Disable All"; - this.buttonDisableAll.UseVisualStyleBackColor = true; - this.buttonDisableAll.Click += new System.EventHandler(this.buttonDisableAll_Click); - // // OptionsWindow // this.AcceptButton = this.buttonOK; @@ -889,6 +976,8 @@ this.tabPlotting.ResumeLayout(false); this.tabPlotting.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.textStep)).EndInit(); + this.tabSymbols.ResumeLayout(false); + this.tabSymbols.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -956,5 +1045,12 @@ private System.Windows.Forms.Button buttonCancel; private System.Windows.Forms.Button buttonDisableAll; private System.Windows.Forms.Button buttonEnableAll; + private System.Windows.Forms.TabPage tabSymbols; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox textSearchPath; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Button buttonDbghelpBrowse; + private System.Windows.Forms.TextBox textDbghelpPath; + private System.Windows.Forms.CheckBox checkUndecorate; } } \ No newline at end of file diff --git a/trunk/ProcessHacker/Forms/OptionsWindow.cs b/trunk/ProcessHacker/Forms/OptionsWindow.cs index 125bc61a3..2c5c0fff0 100644 --- a/trunk/ProcessHacker/Forms/OptionsWindow.cs +++ b/trunk/ProcessHacker/Forms/OptionsWindow.cs @@ -126,7 +126,16 @@ namespace ProcessHacker catch { checkReplaceTaskManager.Enabled = false; + } + + try + { + textDbghelpPath.Text = Properties.Settings.Default.DbgHelpPath; + textSearchPath.Text = Properties.Settings.Default.DbgHelpSearchPath; + checkUndecorate.Checked = (Symbols.Options & Win32.SYMBOL_OPTIONS.UndName) != 0; } + catch + { } checkShowTrayIcon_CheckedChanged(null, null); } @@ -333,6 +342,15 @@ namespace ProcessHacker } } + try + { + Properties.Settings.Default.DbgHelpPath = textDbghelpPath.Text; + Properties.Settings.Default.DbgHelpSearchPath = textSearchPath.Text; + Properties.Settings.Default.DbgHelpUndecorate = checkUndecorate.Checked; + } + catch + { } + Program.HackerWindow.ProcessProvider.Interval = Properties.Settings.Default.RefreshInterval; Program.HackerWindow.ServiceProvider.Interval = Properties.Settings.Default.RefreshInterval; Program.HackerWindow.NetworkProvider.Interval = Properties.Settings.Default.RefreshInterval; @@ -417,5 +435,16 @@ namespace ProcessHacker foreach (ListViewItem item in listHighlightingColors.Items) item.Checked = false; } + + private void buttonDbghelpBrowse_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + ofd.Filter = "dbghelp.dll|dbghelp.dll|DLL files (*.dll)|*.dll|All files (*.*)|*.*"; + ofd.FileName = textDbghelpPath.Text; + + if (ofd.ShowDialog() == DialogResult.OK) + textDbghelpPath.Text = ofd.FileName; + } } } diff --git a/trunk/ProcessHacker/Forms/ThreadWindow.Designer.cs b/trunk/ProcessHacker/Forms/ThreadWindow.Designer.cs index 0e5d86f04..cce5623c6 100644 --- a/trunk/ProcessHacker/Forms/ThreadWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/ThreadWindow.Designer.cs @@ -23,9 +23,6 @@ if (_thandle != null) _thandle.Dispose(); - Program.ThreadWindows.Remove(Id); - Program.UpdateWindows(); - base.Dispose(disposing); } @@ -46,7 +43,6 @@ this.suspendMenuItem = new System.Windows.Forms.MenuItem(); this.resumeMenuItem = new System.Windows.Forms.MenuItem(); this.terminateMenuItem = new System.Windows.Forms.MenuItem(); - this.windowMenuItem = new System.Windows.Forms.MenuItem(); this.timerUpdate = new System.Windows.Forms.Timer(this.components); this.listViewCallStack = new System.Windows.Forms.ListView(); this.columnHeader3 = new System.Windows.Forms.ColumnHeader(); @@ -69,8 +65,7 @@ // mainMenu // this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { - this.threadMenuItem, - this.windowMenuItem}); + this.threadMenuItem}); // // threadMenuItem // @@ -119,11 +114,6 @@ this.terminateMenuItem.Text = "&Terminate"; this.terminateMenuItem.Click += new System.EventHandler(this.terminateMenuItem_Click); // - // windowMenuItem - // - this.windowMenuItem.Index = 1; - this.windowMenuItem.Text = "&Window"; - // // timerUpdate // this.timerUpdate.Enabled = true; @@ -143,7 +133,7 @@ this.listViewCallStack.Location = new System.Drawing.Point(6, 19); this.listViewCallStack.Name = "listViewCallStack"; this.listViewCallStack.ShowItemToolTips = true; - this.listViewCallStack.Size = new System.Drawing.Size(363, 137); + this.listViewCallStack.Size = new System.Drawing.Size(363, 140); this.listViewCallStack.TabIndex = 0; this.listViewCallStack.UseCompatibleStateImageBehavior = false; this.listViewCallStack.View = System.Windows.Forms.View.Details; @@ -170,7 +160,7 @@ this.groupBoxCallStack.Controls.Add(this.listViewCallStack); this.groupBoxCallStack.Location = new System.Drawing.Point(12, 34); this.groupBoxCallStack.Name = "groupBoxCallStack"; - this.groupBoxCallStack.Size = new System.Drawing.Size(375, 191); + this.groupBoxCallStack.Size = new System.Drawing.Size(375, 194); this.groupBoxCallStack.TabIndex = 1; this.groupBoxCallStack.TabStop = false; this.groupBoxCallStack.Text = "Call Stack"; @@ -179,7 +169,7 @@ // this.fileModule.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.fileModule.Location = new System.Drawing.Point(57, 161); + this.fileModule.Location = new System.Drawing.Point(57, 164); this.fileModule.Name = "fileModule"; this.fileModule.ReadOnly = false; this.fileModule.Size = new System.Drawing.Size(231, 24); @@ -189,7 +179,7 @@ // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 167); + this.label1.Location = new System.Drawing.Point(6, 170); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(45, 13); this.label1.TabIndex = 4; @@ -199,7 +189,7 @@ // this.buttonWalk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonWalk.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonWalk.Location = new System.Drawing.Point(294, 162); + this.buttonWalk.Location = new System.Drawing.Point(294, 165); this.buttonWalk.Name = "buttonWalk"; this.buttonWalk.Size = new System.Drawing.Size(75, 23); this.buttonWalk.TabIndex = 3; @@ -212,9 +202,9 @@ this.groupRegisters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.groupRegisters.Controls.Add(this.listViewRegisters); - this.groupRegisters.Location = new System.Drawing.Point(12, 231); + this.groupRegisters.Location = new System.Drawing.Point(12, 234); this.groupRegisters.Name = "groupRegisters"; - this.groupRegisters.Size = new System.Drawing.Size(375, 153); + this.groupRegisters.Size = new System.Drawing.Size(375, 129); this.groupRegisters.TabIndex = 2; this.groupRegisters.TabStop = false; this.groupRegisters.Text = "Registers"; @@ -230,7 +220,7 @@ this.listViewRegisters.FullRowSelect = true; this.listViewRegisters.Location = new System.Drawing.Point(6, 19); this.listViewRegisters.Name = "listViewRegisters"; - this.listViewRegisters.Size = new System.Drawing.Size(363, 128); + this.listViewRegisters.Size = new System.Drawing.Size(363, 104); this.listViewRegisters.TabIndex = 0; this.listViewRegisters.UseCompatibleStateImageBehavior = false; this.listViewRegisters.View = System.Windows.Forms.View.Details; @@ -261,13 +251,17 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(399, 396); + this.ClientSize = new System.Drawing.Size(399, 375); this.Controls.Add(this.labelThreadUser); this.Controls.Add(this.groupRegisters); this.Controls.Add(this.groupBoxCallStack); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; this.Menu = this.mainMenu; + this.MinimizeBox = false; this.Name = "ThreadWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Thread"; this.Load += new System.EventHandler(this.ThreadWindow_Load); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ThreadWindow_FormClosing); @@ -284,7 +278,6 @@ private wyDay.Controls.VistaMenu vistaMenu; private System.Windows.Forms.MainMenu mainMenu; - private System.Windows.Forms.MenuItem windowMenuItem; private System.Windows.Forms.Timer timerUpdate; private System.Windows.Forms.GroupBox groupBoxCallStack; private System.Windows.Forms.ListView listViewCallStack; diff --git a/trunk/ProcessHacker/Forms/ThreadWindow.cs b/trunk/ProcessHacker/Forms/ThreadWindow.cs index 647985738..cd5be44a4 100644 --- a/trunk/ProcessHacker/Forms/ThreadWindow.cs +++ b/trunk/ProcessHacker/Forms/ThreadWindow.cs @@ -33,7 +33,7 @@ namespace ProcessHacker private int _tid; private Win32.ProcessHandle _phandle; private Win32.ThreadHandle _thandle; - private SymbolProvider _symbols; + private Symbols _symbols; public const string DisplayFormat = "0x{0:x8}"; @@ -45,7 +45,7 @@ namespace ProcessHacker get { return _pid + "-" + _tid; } } - public ThreadWindow(int PID, int TID, SymbolProvider symbols) + public ThreadWindow(int PID, int TID, Symbols symbols) { InitializeComponent(); @@ -55,8 +55,6 @@ namespace ProcessHacker _tid = TID; _symbols = symbols; - Program.ThreadWindows.Add(Id, this); - this.Text = Win32.GetNameFromPID(_pid) + " (PID " + _pid.ToString() + ") - Thread " + _tid.ToString(); @@ -109,16 +107,6 @@ namespace ProcessHacker { } } - public MenuItem WindowMenuItem - { - get { return windowMenuItem; } - } - - public wyDay.Controls.VistaMenu VistaMenu - { - get { return vistaMenu; } - } - private void ThreadWindow_Load(object sender, EventArgs e) { listViewCallStack.SetTheme("explorer"); @@ -169,8 +157,6 @@ namespace ProcessHacker this.Size = Properties.Settings.Default.ThreadWindowSize; ColumnSettings.LoadSettings(Properties.Settings.Default.CallStackColumns, listViewCallStack); - - Program.UpdateWindows(); } private void ThreadWindow_FormClosing(object sender, FormClosingEventArgs e) @@ -262,7 +248,7 @@ namespace ProcessHacker //} if (!Win32.StackWalk64(Win32.MachineType.IMAGE_FILE_MACHINE_i386, _phandle, _thandle, - ref stackFrame, ref context, readMemoryProc, null, null, 0)) + ref stackFrame, ref context, readMemoryProc, Win32.SymFunctionTableAccess64, Win32.SymGetModuleBase64, 0)) break; if (stackFrame.AddrPC.Offset == 0) @@ -272,7 +258,7 @@ namespace ProcessHacker ListViewItem newItem = listViewCallStack.Items.Add(new ListViewItem(new string[] { "0x" + addr.ToString("x8"), - _symbols.GetNameFromAddress(addr) + _symbols.GetSymbolFromAddress(addr) })); newItem.Tag = addr; @@ -410,7 +396,10 @@ namespace ProcessHacker { if (listViewCallStack.SelectedItems.Count == 1) { - fileModule.Text = _symbols.GetModuleFromAddress((uint)listViewCallStack.SelectedItems[0].Tag); + string fileName; + + _symbols.GetSymbolFromAddress((uint)listViewCallStack.SelectedItems[0].Tag, out fileName); + fileModule.Text = fileName; fileModule.Enabled = true; } else diff --git a/trunk/ProcessHacker/ProcessHacker.csproj b/trunk/ProcessHacker/ProcessHacker.csproj index be7e0db26..33a3be0a8 100644 --- a/trunk/ProcessHacker/ProcessHacker.csproj +++ b/trunk/ProcessHacker/ProcessHacker.csproj @@ -609,6 +609,7 @@ + @@ -704,7 +705,6 @@ - diff --git a/trunk/ProcessHacker/Program.cs b/trunk/ProcessHacker/Program.cs index dc03ad697..6a3b09ad4 100644 --- a/trunk/ProcessHacker/Program.cs +++ b/trunk/ProcessHacker/Program.cs @@ -70,10 +70,6 @@ namespace ProcessHacker public static Dictionary ResultsWindows = new Dictionary(); public static Dictionary ResultsThreads = new Dictionary(); - public const bool ThreadWindowsThreaded = false; - public static Dictionary ThreadWindows = new Dictionary(); - public static Dictionary ThreadThreads = new Dictionary(); - public const bool PEWindowsThreaded = false; public static Dictionary PEWindows = new Dictionary(); public static Dictionary PEThreads = new Dictionary(); @@ -735,68 +731,6 @@ namespace ProcessHacker return rw; } - /// - /// Creates an instance of the thread window on a separate thread. - /// - public static ThreadWindow GetThreadWindow(int PID, int TID, SymbolProvider symbols) - { - return GetThreadWindow(PID, TID, symbols, new ThreadWindowInvokeAction(delegate { })); - } - - /// - /// Creates an instance of the thread window on a separate thread and invokes an action on that thread. - /// - /// The action to be performed. - public static ThreadWindow GetThreadWindow(int PID, int TID, SymbolProvider symbols, ThreadWindowInvokeAction action) - { - ThreadWindow tw = null; - string id = PID + "-" + TID; - - if (ThreadWindows.ContainsKey(id)) - { - tw = ThreadWindows[id]; - - tw.Invoke(action, tw); - - return tw; - } - - if (ThreadWindowsThreaded) - { - Thread t = new Thread(new ThreadStart(delegate - { - tw = new ThreadWindow(PID, TID, symbols); - - id = tw.Id; - - action(tw); - - try - { - Application.Run(tw); - } - catch - { } - - Program.ThreadThreads.Remove(id); - })); - - t.SetApartmentState(ApartmentState.STA); - t.Start(); - - while (id == "") Thread.Sleep(1); - Program.ThreadThreads.Add(id, t); - } - else - { - tw = new ThreadWindow(PID, TID, symbols); - action(tw); - tw.Show(); - } - - return tw; - } - /// /// Creates an instance of the PE window on a separate thread. /// @@ -1011,7 +945,6 @@ namespace ProcessHacker dics.Add(Program.MemoryEditors); dics.Add(Program.ResultsWindows); - dics.Add(Program.ThreadWindows); dics.Add(Program.PEWindows); dics.Add(Program.PWindows); diff --git a/trunk/ProcessHacker/Properties/Settings.Designer.cs b/trunk/ProcessHacker/Properties/Settings.Designer.cs index 1a56dd8a3..021bea96f 100644 --- a/trunk/ProcessHacker/Properties/Settings.Designer.cs +++ b/trunk/ProcessHacker/Properties/Settings.Designer.cs @@ -1248,5 +1248,41 @@ namespace ProcessHacker.Properties { this["UseColorGuiThreads"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("dbghelp.dll")] + public string DbgHelpPath { + get { + return ((string)(this["DbgHelpPath"])); + } + set { + this["DbgHelpPath"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string DbgHelpSearchPath { + get { + return ((string)(this["DbgHelpSearchPath"])); + } + set { + this["DbgHelpSearchPath"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool DbgHelpUndecorate { + get { + return ((bool)(this["DbgHelpUndecorate"])); + } + set { + this["DbgHelpUndecorate"] = value; + } + } } } diff --git a/trunk/ProcessHacker/Properties/Settings.settings b/trunk/ProcessHacker/Properties/Settings.settings index e631f1d1d..132b4996b 100644 --- a/trunk/ProcessHacker/Properties/Settings.settings +++ b/trunk/ProcessHacker/Properties/Settings.settings @@ -308,5 +308,14 @@ True + + dbghelp.dll + + + + + + True + \ No newline at end of file diff --git a/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs b/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs index 4681480fe..c43f9527a 100644 --- a/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs +++ b/trunk/ProcessHacker/Providers/ProcessSystemProvider.cs @@ -89,8 +89,6 @@ namespace ProcessHacker public class ProcessSystemProvider : Provider { - private const bool CacheFileVerifyResults = false; - public class FileProcessResult { public int PID; @@ -110,7 +108,7 @@ namespace ProcessHacker private HistoryManager _floatHistory = new HistoryManager(); private HistoryManager _mostUsageHistory = new HistoryManager(); - private delegate void ProcessFileDelegate(int pid, string fileName); + private delegate void ProcessFileDelegate(int pid, string fileName, bool useCache); public ProcessSystemProvider() : base() @@ -233,7 +231,7 @@ namespace ProcessHacker this.Performance = performance; } - private void ProcessFile(int pid, string fileName) + private void ProcessFile(int pid, string fileName, bool forced) { FileProcessResult fpResult = new FileProcessResult(); @@ -248,7 +246,7 @@ namespace ProcessHacker // 1. the function-to-library ratio is lower than 4 // (on average less than 4 functions are imported from each library) // 2. it references more than 3 libraries but less than 14 libraries. - if (fileName != null) + if (fileName != null && (Properties.Settings.Default.VerifySignatures || forced)) { try { @@ -294,7 +292,7 @@ namespace ProcessHacker try { - if (Properties.Settings.Default.VerifySignatures) + if (Properties.Settings.Default.VerifySignatures || forced) { if (fileName != null) { @@ -302,7 +300,7 @@ namespace ProcessHacker lock (_fileResults) { - if (CacheFileVerifyResults && _fileResults.ContainsKey(uniName)) + if (!forced && _fileResults.ContainsKey(uniName)) { fpResult.VerifyResult = _fileResults[uniName]; } @@ -317,7 +315,10 @@ namespace ProcessHacker fpResult.VerifyResult = Win32.VerifyResult.NoSignature; } - //_fileResults.Add(uniName, fpResult.VerifyResult); + if (!_fileResults.ContainsKey(uniName)) + _fileResults.Add(uniName, fpResult.VerifyResult); + else + _fileResults[uniName] = fpResult.VerifyResult; } } } @@ -366,7 +367,7 @@ namespace ProcessHacker public void QueueFileProcessing(int pid) { - (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, this.Dictionary[pid].FileName, + (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, this.Dictionary[pid].FileName, true, r => { }, null); } @@ -747,7 +748,7 @@ namespace ProcessHacker if (pid > 0) { - (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, item.FileName, + (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, item.FileName, false, r => { }, null); } @@ -866,9 +867,9 @@ namespace ProcessHacker if (pid > 0) { - if (item.IsPacked && item.ProcessingAttempts < 5) + if (item.IsPacked && item.ProcessingAttempts < 3) { - (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, item.FileName, + (new ProcessFileDelegate(this.ProcessFile)).BeginInvoke(pid, item.FileName, true, r => { }, null); item.ProcessingAttempts++; } diff --git a/trunk/ProcessHacker/Providers/ThreadProvider.cs b/trunk/ProcessHacker/Providers/ThreadProvider.cs index 84c40479d..e5f8ef9f3 100644 --- a/trunk/ProcessHacker/Providers/ThreadProvider.cs +++ b/trunk/ProcessHacker/Providers/ThreadProvider.cs @@ -47,14 +47,23 @@ namespace ProcessHacker public string StartAddress; public Win32.KWAIT_REASON WaitReason; public bool IsGuiThread; + public bool JustResolved; public Win32.ThreadHandle ThreadQueryLimitedHandle; } public class ThreadProvider : Provider { - private SymbolProvider _symbols = new SymbolProvider(); + public delegate void LoadingStateChangedDelegate(bool loading); + private delegate void ResolveThreadStartAddressDelegate(int tid, long startAddress); + + public event LoadingStateChangedDelegate LoadingStateChanged; + + private Win32.ProcessHandle _processHandle; + private Symbols _symbols; private int _pid; + private int _loading = 0; + private Queue> _resolveResults = new Queue>(); public ThreadProvider(int PID) : base() @@ -67,50 +76,67 @@ namespace ProcessHacker this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); this.Killed += new MethodInvoker(ThreadProvider_Killed); - // start loading symbols - ThreadPool.QueueUserWorkItem(new WaitCallback(o => + try { - try + _processHandle = new Win32.ProcessHandle(_pid, Program.MinProcessQueryRights); + _symbols = new Symbols(_processHandle); + + Symbols.Options = Win32.SYMBOL_OPTIONS.DeferredLoads | Win32.SYMBOL_OPTIONS.NoPrompts | + (Properties.Settings.Default.DbgHelpUndecorate ? Win32.SYMBOL_OPTIONS.UndName : 0); + + if (Properties.Settings.Default.DbgHelpSearchPath != "") + _symbols.SearchPath = Properties.Settings.Default.DbgHelpSearchPath; + + // start loading symbols + ThreadPool.QueueUserWorkItem(new WaitCallback(o => { - if (_pid != 4) + try { - using (var phandle = - new Win32.ProcessHandle(_pid, Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + if (_pid != 4) { - foreach (var module in phandle.GetModules()) + using (var phandle = + new Win32.ProcessHandle(_pid, Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + foreach (var module in phandle.GetModules()) + { + try + { + _symbols.LoadModule(module.FileName, module.BaseAddress.ToInt32(), module.Size); + } + catch + { } + } + } + } + else + { + // load driver symbols + foreach (var module in Win32.EnumKernelModules()) { try { - _symbols.LoadSymbolsFromLibrary(module.FileName, (uint)module.BaseAddress.ToInt32()); + _symbols.LoadModule(module.FileName, module.BaseAddress); } catch { } } } } - else - { - // load driver symbols - foreach (var module in Win32.EnumKernelModules()) - { - try - { - _symbols.LoadSymbolsFromLibrary(module.FileName, module.BaseAddress); - } - catch - { } - } - } - } - catch - { } - - Program.CollectGarbage(); - })); + catch + { } + })); + } + catch + { } } private void ThreadProvider_Killed() { + if (_symbols != null) + _symbols.Dispose(); + if (_processHandle != null) + _processHandle.Dispose(); + if (Win32.ProcessesWithThreads.ContainsKey(_pid)) Win32.ProcessesWithThreads.Remove(_pid); @@ -123,6 +149,36 @@ namespace ProcessHacker } } + private void ResolveThreadStartAddress(int tid, long startAddress) + { + string name = null; + + try + { + _loading++; + + if (this.LoadingStateChanged != null) + this.LoadingStateChanged(_loading > 0); + + try + { + name = _symbols.GetSymbolFromAddress(startAddress); + + lock (_resolveResults) + _resolveResults.Enqueue(new KeyValuePair(tid, name)); + } + catch + { } + } + finally + { + _loading--; + + if (this.LoadingStateChanged != null) + this.LoadingStateChanged(_loading > 0); + } + } + private void UpdateOnce() { Dictionary threads = @@ -147,6 +203,20 @@ namespace ProcessHacker } } + lock (_resolveResults) + { + while (_resolveResults.Count > 0) + { + var result = _resolveResults.Dequeue(); + + if (result.Value != null) + { + this.Dictionary[result.Key].StartAddress = result.Value; + this.Dictionary[result.Key].JustResolved = true; + } + } + } + // look for new threads foreach (int tid in threads.Keys) { @@ -223,11 +293,21 @@ namespace ProcessHacker try { - item.StartAddress = _symbols.GetNameFromAddress(item.StartAddressI); + long modBase; + string fileName = _symbols.GetModuleFromAddress(item.StartAddressI, out modBase); + + if (fileName == null) + item.StartAddress = "0x" + item.StartAddressI.ToString("x"); + else + item.StartAddress = (new System.IO.FileInfo(fileName)).Name + "+0x" + + (item.StartAddressI - modBase).ToString("x"); } catch { } + (new ResolveThreadStartAddressDelegate(this.ResolveThreadStartAddress)).BeginInvoke( + tid, item.StartAddressI, r => { }, null); + newdictionary.Add(tid, item); this.CallDictionaryAdded(item); } @@ -237,6 +317,7 @@ namespace ProcessHacker ThreadItem item = Dictionary[tid]; ThreadItem newitem = item.Clone() as ThreadItem; + newitem.JustResolved = false; newitem.ContextSwitchesDelta = t.ContextSwitchCount - newitem.ContextSwitches; newitem.ContextSwitches = t.ContextSwitchCount; newitem.WaitReason = t.WaitReason; @@ -271,18 +352,7 @@ namespace ProcessHacker { } } - try - { - SymbolProvider.FoundLevel level; - - string symName = _symbols.GetNameFromAddress(newitem.StartAddressI, out level); - - if (level != SymbolProvider.FoundLevel.Address) - newitem.StartAddress = symName; - } - catch { } - - if ( + if ( newitem.ContextSwitches != item.ContextSwitches || newitem.ContextSwitchesDelta != item.ContextSwitchesDelta || newitem.Cycles != item.Cycles || @@ -290,7 +360,8 @@ namespace ProcessHacker newitem.IsGuiThread != item.IsGuiThread || newitem.Priority != item.Priority || newitem.StartAddress != item.StartAddress || - newitem.WaitReason != item.WaitReason + newitem.WaitReason != item.WaitReason || + item.JustResolved ) { newdictionary[tid] = newitem; @@ -302,7 +373,7 @@ namespace ProcessHacker Dictionary = newdictionary; } - public SymbolProvider Symbols + public Symbols Symbols { get { return _symbols; } } diff --git a/trunk/ProcessHacker/Singleton.cs b/trunk/ProcessHacker/Singleton.cs index 36c949df5..987212c0f 100644 --- a/trunk/ProcessHacker/Singleton.cs +++ b/trunk/ProcessHacker/Singleton.cs @@ -6,13 +6,13 @@ public class Singleton where T : class, new() { - private object _instanceLock = new object(); - private T _instance = null; + private static object _instanceLock = new object(); + private static T _instance = null; /// /// The single instance of the type. /// - public T Instance + public static T Instance { get { diff --git a/trunk/ProcessHacker/Symbols/SymbolProvider.cs b/trunk/ProcessHacker/Symbols/SymbolProvider.cs deleted file mode 100644 index af132dde1..000000000 --- a/trunk/ProcessHacker/Symbols/SymbolProvider.cs +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Process Hacker - - * symbol server - * - * Copyright (C) 2008-2009 wj32 - * - * This file is part of Process Hacker. - * - * Process Hacker is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Process Hacker is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Process Hacker. If not, see . - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using ProcessHacker.PE; - -namespace ProcessHacker -{ - /// - /// Provides services for retrieving symbol information. - /// - public class SymbolProvider - { - public static SymbolProvider BaseInstance { get; private set; } - - static SymbolProvider() - { - SymbolProvider.BaseInstance = new SymbolProvider(); - } - - /// - /// Specifies the detail with which the address's name was resolved. - /// - public enum FoundLevel - { - /// - /// Indicates that the address was resolved to a module, a function and possibly an offset. - /// For example: mymodule.dll!MyExportedFunction+0x123 - /// - Function, - - /// - /// Indicates that the address was resolved to a module and an offset. - /// For example: mymodule.dll+0x4321 - /// - Module, - - /// - /// Indicates that the address was not resolved. - /// For example: 0x12345678 - /// - Address, - - /// - /// Indicates that the address was invalid (for example, 0x0). - /// - Invalid - } - - private List> _libraryLookup; - private Dictionary>> _symbols; - private Dictionary _librarySizes; - - public SymbolProvider() - { - if (SymbolProvider.BaseInstance != null) - { - _libraryLookup = new List>(SymbolProvider.BaseInstance._libraryLookup); - _symbols = new Dictionary>>(SymbolProvider.BaseInstance._symbols); - _librarySizes = new Dictionary(SymbolProvider.BaseInstance._librarySizes); - } - else - { - _libraryLookup = new List>(); - _symbols = new Dictionary>>(); - _librarySizes = new Dictionary(); - } - } - - //public void LoadSymbolsFromLibrary(string path) - //{ - // LoadSymbolsFromLibrary(path, Process.GetCurrentProcess().Modules); - //} - - //public void LoadSymbolsFromLibrary(string path, ProcessModuleCollection modules) - //{ - // string realPath = Misc.GetRealPath(path).ToLower(); - // uint imageBase = 0; - - // foreach (ProcessModule module in modules) - // { - // string thisPath = Misc.GetRealPath(module.FileName).ToLower(); - - // if (thisPath == realPath) - // { - // imageBase = (uint)module.BaseAddress.ToInt32(); - // break; - // } - // } - - // if (imageBase == 0) - // throw new Exception("Could not get image base of library."); - - // LoadSymbolsFromLibrary(path, imageBase); - //} - - public void LoadSymbolsFromLibrary(string path, uint imageBase) - { - string realPath = Misc.GetRealPath(path).ToLower(); - - // check if it is already loaded - if (_symbols.ContainsKey(realPath)) - return; - - PEFile file = null; - List> list = new List>(); - - try - { - file = new PEFile(realPath); - - uint size = 0; - - foreach (SectionHeader sh in file.Sections) - size += sh.VirtualSize; - - _librarySizes.Add(realPath, size); - } - catch - { } - - if (file == null || file.ExportData == null) - { - // no symbols (or error), but we can still display a module name in a lookup - _libraryLookup.Add(new KeyValuePair(imageBase, realPath)); - _symbols.Add(realPath, new List>()); - - // if we didn't even get to load the PE file - if (!_librarySizes.ContainsKey(realPath)) - _librarySizes.Add(realPath, 0xffffffff); - } - else - { - for (int i = 0; i < file.ExportData.ExportOrdinalTable.Count; i++) - { - ushort ordinal = file.ExportData.ExportOrdinalTable[i]; - - if (ordinal >= file.ExportData.ExportAddressTable.Count) - continue; - - uint address = file.ExportData.ExportAddressTable[ordinal].ExportRVA; - - string name; - - if (i < file.ExportData.ExportNameTable.Count) - name = file.ExportData.ExportNameTable[i]; - else - name = ordinal.ToString(); - - list.Add(new KeyValuePair(imageBase + address, name)); - } - - _libraryLookup.Add(new KeyValuePair(imageBase, realPath)); - _symbols.Add(realPath, list); - } - - // sort the list - list.Sort(new Comparison>( - delegate(KeyValuePair kvp1, KeyValuePair kvp2) - { - return (kvp2.Key).CompareTo(kvp1.Key); - })); - - _libraryLookup.Sort(new Comparison>( - delegate(KeyValuePair kvp1, KeyValuePair kvp2) - { - return (kvp2.Key).CompareTo(kvp1.Key); - })); - } - - public void UnloadSymbols(string path) - { - foreach (var kvp in _libraryLookup) - { - if (kvp.Value == path) - { - _libraryLookup.Remove(kvp); - break; - } - } - - _librarySizes.Remove(path); - _symbols.Remove(path); - } - - public string GetModuleFromAddress(uint address) - { - foreach (var kvp in _libraryLookup) - { - if (address >= kvp.Key) - { - var symbolList = _symbols[kvp.Value]; - FileInfo fi = new FileInfo(kvp.Value); - - return fi.FullName; - } - } - - return ""; - } - - public string GetNameFromAddress(uint address) - { - FoundLevel level; - - return GetNameFromAddress(address, out level); - } - - public string GetNameFromAddress(uint address, out FoundLevel level) - { - if (address == 0) - { - level = FoundLevel.Invalid; - return "0x0"; - } - - // go through each loaded library - foreach (var kvp in _libraryLookup) - { - uint size = _librarySizes[kvp.Value]; - - //if ((uint)address >= (uint)kvp.Key && (uint)address < ((uint)kvp.Key + size)) - if (address >= kvp.Key) - { - var symbolList = _symbols[kvp.Value]; - FileInfo fi = new FileInfo(kvp.Value); - - // go through each symbol - foreach (var kvps in symbolList) - { - if (address >= kvps.Key) - { - // we found a function name - uint offset = address - kvps.Key; - - level = FoundLevel.Function; - - // don't need to put in the + - if (offset == 0) - return string.Format("{0}!{1}", fi.Name, kvps.Value); - else - return string.Format("{0}!{1}+0x{2:x}", - fi.Name, kvps.Value, address - kvps.Key); - } - } - - // no function name found, but we have a library name - level = FoundLevel.Module; - return string.Format("{0}+0x{1:x}", fi.Name, address - kvp.Key); - } - } - - // we didn't find anything - level = FoundLevel.Address; - return "0x" + address.ToString("x8"); - } - - public int LibraryCount - { - get { return _libraryLookup.Count; } - } - - public int SymbolCount - { - get - { - int count = 0; - - foreach (var list in _symbols.Values) - count += list.Count; - - return count; - } - } - - public IEnumerable Keys - { - get - { - return _symbols.Keys; - } - } - } -} diff --git a/trunk/ProcessHacker/Symbols/Symbols.cs b/trunk/ProcessHacker/Symbols/Symbols.cs new file mode 100644 index 000000000..b51136415 --- /dev/null +++ b/trunk/ProcessHacker/Symbols/Symbols.cs @@ -0,0 +1,322 @@ +/* + * Process Hacker - + * dbghelp.dll wrapper code + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Threading; + +namespace ProcessHacker +{ + public class Symbols : IDisposable + { + /// + /// Specifies the detail with which the address's name was resolved. + /// + public enum FoundLevel + { + /// + /// Indicates that the address was resolved to a module, a function and possibly an offset. + /// For example: mymodule.dll!MyExportedFunction+0x123 + /// + Function, + + /// + /// Indicates that the address was resolved to a module and an offset. + /// For example: mymodule.dll+0x4321 + /// + Module, + + /// + /// Indicates that the address was not resolved. + /// For example: 0x12345678 + /// + Address, + + /// + /// Indicates that the address was invalid (for example, 0x0). + /// + Invalid + } + + private static object _callLock = new object(); + private static IdGenerator _idGen = new IdGenerator(); + + public static Win32.SYMBOL_OPTIONS Options + { + get + { + lock (_callLock) + return Win32.SymGetOptions(); + } + + set + { + lock (_callLock) + Win32.SymSetOptions(value); + } + } + + private bool _disposed = false; + private object _disposeLock = new object(); + private Win32.ProcessHandle _processHandle; + private int _handle; + private List> _modules = new List>(); + + public Symbols() + { + _handle = _idGen.Pop(); + + lock (_callLock) + { + if (!Win32.SymInitialize(_handle, null, false)) + Win32.ThrowLastWin32Error(); + } + } + + public Symbols(Win32.ProcessHandle processHandle) + { + _processHandle = processHandle; + _handle = processHandle; + + lock (_callLock) + { + if (!Win32.SymInitialize(_handle, null, false)) + Win32.ThrowLastWin32Error(); + } + } + + public int Handle + { + get { return _handle; } + } + + public string SearchPath + { + get + { + using (var data = new MemoryAlloc(0x1000)) + { + lock (_callLock) + { + if (!Win32.SymGetSearchPath(_handle, data, data.Size)) + return ""; + } + + return Marshal.PtrToStringAnsi(data); + } + } + + set + { + lock (_callLock) + Win32.SymSetSearchPath(_handle, value); + } + } + + public void LoadModule(string fileName, long baseAddress) + { + this.LoadModule(fileName, baseAddress, 0); + } + + public void LoadModule(string fileName, long baseAddress, int size) + { + lock (_callLock) + { + if (Win32.SymLoadModule64(_handle, 0, fileName, null, baseAddress, size) == 0) + Win32.ThrowLastWin32Error(); + } + + lock (_modules) + { + _modules.Add(new KeyValuePair(baseAddress, fileName)); + _modules.Sort(new Comparison>( + (kvp1, kvp2) => kvp2.Key.CompareTo(kvp1.Key))); + } + } + + public string GetModuleFromAddress(long address, out long baseAddress) + { + lock (_modules) + { + foreach (var kvp in _modules) + { + if (address >= kvp.Key) + { + baseAddress = kvp.Key; + return kvp.Value; + } + } + } + + baseAddress = 0; + + return null; + } + + public string GetSymbolFromAddress(long address) + { + Win32.SYMBOL_FLAGS flags; + + return this.GetSymbolFromAddress(address, out flags); + } + + public string GetSymbolFromAddress(long address, out FoundLevel level) + { + Win32.SYMBOL_FLAGS flags; + string fileName; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(long address, out Win32.SYMBOL_FLAGS flags) + { + FoundLevel level; + string fileName; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(long address, out string fileName) + { + FoundLevel level; + Win32.SYMBOL_FLAGS flags; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(long address, out FoundLevel level, out Win32.SYMBOL_FLAGS flags, out string fileName) + { + const int maxNameLen = 0x400; + long displacement; + + if (address == 0) + { + level = FoundLevel.Invalid; + flags = 0; + fileName = null; + } + + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(Win32.SYMBOL_INFO)) + maxNameLen)) + { + Win32.SYMBOL_INFO info = new Win32.SYMBOL_INFO(); + + info.SizeOfStruct = Marshal.SizeOf(info); + info.MaxNameLen = maxNameLen - 1; + + Marshal.StructureToPtr(info, data, false); + + lock (_callLock) + { + if (Win32.SymFromAddr(_handle, address, out displacement, data)) + { + info = data.ReadStruct(); + } + } + + string modFileName; + long modBase; + + if (info.ModBase == 0) + { + modFileName = this.GetModuleFromAddress(address, out modBase); + } + else + { + modBase = info.ModBase; + modFileName = _modules.Find( + new Predicate>(kvp => kvp.Key == info.ModBase)).Value; + } + + if (modFileName == null) + { + level = FoundLevel.Address; + flags = 0; + fileName = null; + + return "0x" + address.ToString("x8"); + } + + System.IO.FileInfo fi = new System.IO.FileInfo(modFileName); + + fileName = fi.FullName; + + if (info.NameLen == 0) + { + level = FoundLevel.Module; + flags = 0; + + return fi.Name + "+0x" + (address - modBase).ToString("x"); + } + + string name = Marshal.PtrToStringAnsi( + new IntPtr(data + Marshal.OffsetOf(typeof(Win32.SYMBOL_INFO), "Name").ToInt32()), info.NameLen); + + level = FoundLevel.Function; + flags = info.Flags; + + if (displacement == 0) + return fi.Name + "!" + name; + else + return fi.Name + "!" + name + "+0x" + displacement.ToString("x"); + } + } + + ~Symbols() + { + this.Dispose(false); + } + + private void Dispose(bool disposing) + { + try + { + if (disposing) + { + Monitor.Enter(_disposeLock); + Monitor.Enter(_callLock); + } + + if (!_disposed) + { + _disposed = true; + Win32.SymCleanup(_handle); + } + } + finally + { + if (disposing) + { + Monitor.Exit(_callLock); + Monitor.Exit(_disposeLock); + } + } + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/trunk/ProcessHacker/Win32/API/Enums.cs b/trunk/ProcessHacker/Win32/API/Enums.cs index f2b334f6d..a2731ffa0 100644 --- a/trunk/ProcessHacker/Win32/API/Enums.cs +++ b/trunk/ProcessHacker/Win32/API/Enums.cs @@ -871,6 +871,37 @@ namespace ProcessHacker SYMFLAG_VIRTUAL = 0x00001000 } + [Flags] + public enum SYMBOL_OPTIONS : uint + { + AllowAbsoluteSymbols = 0x00000800, + AllowZeroAddress = 0x01000000, + AutoPublics = 0x00010000, + CaseInsensitive = 0x00000001, + Debug = 0x80000000, + DeferredLoads = 0x00000004, + DisableSymSrvAutodetect = 0x02000000, + ExactSymbols = 0x00000400, + FailCriticalErrors = 0x00000200, + FavorCompressed = 0x00800000, + FlatDirectory = 0x00400000, + IgnoreCvRec = 0x00000080, + IgnoreImageDir = 0x00200000, + IgnoreNtSymPath = 0x00001000, + Include32BitModules = 0x00002000, + LoadAnything = 0x00000040, + LoadLines = 0x00000010, + NoCpp = 0x00000008, + NoImageSearch = 0x00020000, + NoPrompts = 0x00080000, + NoPublics = 0x00008000, + NoUnqualifiedLoads = 0x00000100, + Overwrite = 0x00100000, + PublicsOnly = 0x00004000, + Secure = 0x00040000, + UndName = 0x00000002 + } + [Flags] public enum SYNC_RIGHTS : int { diff --git a/trunk/ProcessHacker/Win32/API/Functions.cs b/trunk/ProcessHacker/Win32/API/Functions.cs index 4b527a52d..b578a4fc7 100644 --- a/trunk/ProcessHacker/Win32/API/Functions.cs +++ b/trunk/ProcessHacker/Win32/API/Functions.cs @@ -713,40 +713,74 @@ namespace ProcessHacker #region Symbols/Stack Walking - [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymCleanup(int ProcessHandle); + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool SymInitialize(int ProcessHandle, string UserSearchPath, bool InvadeProcess); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymEnumSymbols(int ProcessHandle, int BaseOfDll, int Mask, - [MarshalAs(UnmanagedType.FunctionPtr)] SymEnumSymbolsProc EnumSymbolsCallback, int UserContext); + public static extern bool SymCleanup(int ProcessHandle); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymEnumSymbols(int ProcessHandle, int BaseOfDll, string Mask, - [MarshalAs(UnmanagedType.FunctionPtr)] SymEnumSymbolsProc EnumSymbolsCallback, int UserContext); + public static extern SYMBOL_OPTIONS SymGetOptions(); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymFromAddr(int ProcessHandle, long Address, ref long Displacement, ref SYMBOL_INFO Symbol); + public static extern SYMBOL_OPTIONS SymSetOptions(SYMBOL_OPTIONS SymOptions); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool SymGetSearchPath(int ProcessHandle, IntPtr SearchPath, int SearchPathLength); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool SymSetSearchPath(int ProcessHandle, string SearchPath); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern long SymLoadModule64( + int ProcessHandle, + int FileHandle, + string ImageName, + string ModuleName, + long BaseOfDll, + int SizeOfDll + ); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymFromIndex(int ProcessHandle, int BaseOfDll, int Index, ref SYMBOL_INFO Symbol); + public static extern int SymFunctionTableAccess64(int ProcessHandle, long AddrBase); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymFunctionTableAccess64(int ProcessHandle, int AddrBase); + public static extern long SymGetModuleBase64(int ProcessHandle, long Address); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymGetModuleBase64(int ProcessHandle, int dwAddr); + public static extern int SymEnumSymbols( + int ProcessHandle, + int BaseOfDll, + string Mask, + SymEnumSymbolsProc EnumSymbolsCallback, int UserContext); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern int SymInitialize(int ProcessHandle, int UserSearchPath, int InvadeProcess); + public static extern bool SymFromAddr( + int ProcessHandle, + long Address, + out long Displacement, + IntPtr Symbol); [DllImport("dbghelp.dll", SetLastError = true)] - public static extern bool StackWalk64(MachineType MachineType, int ProcessHandle, int ThreadHandle, - [MarshalAs(UnmanagedType.Struct)] ref STACKFRAME64 StackFrame, - [MarshalAs(UnmanagedType.Struct)] ref CONTEXT ContextRecord, - [MarshalAs(UnmanagedType.FunctionPtr)] ReadProcessMemoryProc64 ReadMemoryRoutine, - [MarshalAs(UnmanagedType.FunctionPtr)] FunctionTableAccessProc64 FunctionTableAccessRoutine, - [MarshalAs(UnmanagedType.FunctionPtr)] GetModuleBaseProc64 GetModuleBaseRoutine, - int TranslateAddress); + public static extern bool SymFromIndex( + int ProcessHandle, + int BaseOfDll, + int Index, + IntPtr Symbol + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern bool StackWalk64( + MachineType MachineType, + int ProcessHandle, + int ThreadHandle, + ref STACKFRAME64 StackFrame, + ref CONTEXT ContextRecord, + ReadProcessMemoryProc64 ReadMemoryRoutine, + FunctionTableAccessProc64 FunctionTableAccessRoutine, + GetModuleBaseProc64 GetModuleBaseRoutine, + int TranslateAddress + ); #endregion diff --git a/trunk/ProcessHacker/Win32/API/Structs.cs b/trunk/ProcessHacker/Win32/API/Structs.cs index 9e0072314..be6dc1d41 100644 --- a/trunk/ProcessHacker/Win32/API/Structs.cs +++ b/trunk/ProcessHacker/Win32/API/Structs.cs @@ -841,10 +841,7 @@ namespace ProcessHacker { public int SizeOfStruct; public int TypeIndex; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public long[] Reserved; - + public unsafe fixed long Reserved[2]; public int Index; public int Size; public long ModBase; @@ -856,9 +853,7 @@ namespace ProcessHacker public int Tag; public int NameLen; public int MaxNameLen; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SYMBOL_NAME_MAXSIZE)] - public string Name; + public char Name; } [StructLayout(LayoutKind.Sequential)] diff --git a/trunk/ProcessHacker/Win32/Win32.cs b/trunk/ProcessHacker/Win32/Win32.cs index e441b4cab..d96c05fc8 100644 --- a/trunk/ProcessHacker/Win32/Win32.cs +++ b/trunk/ProcessHacker/Win32/Win32.cs @@ -109,11 +109,12 @@ namespace ProcessHacker public delegate bool EnumChildProc(IntPtr hWnd, int param); public delegate bool EnumThreadWndProc(IntPtr hWnd, int param); public delegate IntPtr WndProcDelegate(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam); - public delegate int SymEnumSymbolsProc(SYMBOL_INFO pSymInfo, int SymbolSize, int UserContext); + + public delegate int SymEnumSymbolsProc(IntPtr pSymInfo, int SymbolSize, int UserContext); public delegate bool ReadProcessMemoryProc64(int ProcessHandle, ulong BaseAddress, byte[] Buffer, int Size, out int BytesRead); public delegate int FunctionTableAccessProc64(int ProcessHandle, long AddrBase); - public delegate int GetModuleBaseProc64(int ProcessHandle, long Address); + public delegate long GetModuleBaseProc64(int ProcessHandle, long Address); /// /// A cache for type names; QuerySystemInformation with ALL_TYPES_INFORMATION fails for some @@ -140,7 +141,6 @@ namespace ProcessHacker public const int SID_SIZE = 0x1000; public const int SIZE_OF_80387_REGISTERS = 72; public const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; - public const int SYMBOL_NAME_MAXSIZE = 255; #endregion diff --git a/trunk/ProcessHacker/app.config b/trunk/ProcessHacker/app.config index 16b22e8fd..322aeb672 100644 --- a/trunk/ProcessHacker/app.config +++ b/trunk/ProcessHacker/app.config @@ -313,6 +313,15 @@ True + + dbghelp.dll + + + + + + True + \ No newline at end of file