} // end _TryLoadAssembly() public static void LoadPlugin(string path, IPipelineCallback pipeline) { _EnsureInitialized(); pipeline.WriteVerbose("Looking for plugin types in: {0}", path); Assembly asm = _TryLoadAssembly(path, pipeline); if (null == asm) { return; // already wrote an error } Type dtdPluginInterface = typeof(IDbgDerivedTypeDetectionPlugin); foreach (var candidateType in asm.GetExportedTypes()) { if (dtdPluginInterface.IsAssignableFrom(candidateType)) { pipeline.WriteVerbose("Found Derived Type Detection plugin type: {0}", candidateType.FullName); var constructor = candidateType.GetConstructor(Type.EmptyTypes); if (null == constructor) { DbgProviderException dpe = new DbgProviderException(Util.Sprintf("The plugin type '{0}' from '{1}' cannot be used because it has no public, parameterless constructor.", candidateType.FullName, path), "PluginTypeMissingDefaultConstructor", System.Management.Automation.ErrorCategory.InvalidData, candidateType); try { throw dpe; } catch (Exception) { } // give it a stack pipeline.WriteError(dpe); } try { var plugin = (IDbgDerivedTypeDetectionPlugin)constructor.Invoke(null); sm_dtdPlugins.Add(plugin); pipeline.WriteVerbose("Registered Derived Type Detection plugin: {0}", plugin.Name); } catch (Exception e) // I hate this. { DbgProviderException dpe = new DbgProviderException(Util.Sprintf("The plugin type '{0}' from '{1}' cannot be used because its constructor threw an exception: {2}", candidateType.FullName, path, Util.GetExceptionMessages(e)), "PluginTypeConstructorThrew", System.Management.Automation.ErrorCategory.OpenError, e, candidateType); try { throw dpe; } catch (Exception) { } // give it a stack pipeline.WriteError(dpe); } } // end if( it's a DTD plugin type ) } // end foreach( candidateType ) } // end LoadPlugin()
} // end TryFindPossibleOffsetFromDerivedClass() private static Assembly _TryLoadAssembly(string path, IPipelineCallback pipeline) { Exception e = null; try { return(Assembly.LoadFrom(path)); } catch (BadImageFormatException bife) { e = bife; } catch (System.IO.IOException ioe) { e = ioe; } catch (System.Security.SecurityException se) { e = se; } var dpe = new DbgProviderException(Util.Sprintf("Could not load {0}: {1}", System.IO.Path.GetFileName(path), Util.GetExceptionMessages(e)), "PluginLoadFailed", System.Management.Automation.ErrorCategory.OpenError, e, path); try { throw dpe; } catch (Exception) { } // give it a stack pipeline.WriteError(dpe); return(null); } // end _TryLoadAssembly()
} // end constructor public void AddLine(string s) { switch (m_state) { case WfdState.ExpectingBlockId: if ((s.Length > 0) && (s[s.Length - 1] != ':')) { // It's not a block ID... this can happen when "Flow // analysis was incomplete". m_currentBlockId = new ColorString(ConsoleColor.DarkGray, "<unknown>").MakeReadOnly(); m_pipeline.WriteObject(_ParseDisassembly(0, // will get parsed out of s s, m_currentBlockId, m_hasCodeBytes)); } else { m_currentBlockId = DbgProvider.ColorizeSymbol(s).MakeReadOnly(); } m_state = WfdState.ExpectingInstructionOrBlankLine; break; case WfdState.ExpectingInstructionOrBlankLine: if (String.IsNullOrEmpty(s)) { m_state = WfdState.ExpectingBlockId; m_currentBlockId = null; } else { m_pipeline.WriteObject(_ParseDisassembly(0, // will get parsed out of s s, m_currentBlockId, m_hasCodeBytes)); } break; // This is a horrible state. But sometimes we see it, like // sometimes after a flow analysis error. case WfdState.DontKnow: if (s.StartsWith("Flow analysis", StringComparison.OrdinalIgnoreCase)) { //m_flowAnalysisWarning = true; m_pipeline.WriteWarning(s); m_state = WfdState.DontKnow; break; } else if (s.StartsWith("*** WARNING: ", StringComparison.OrdinalIgnoreCase)) { m_pipeline.WriteWarning(s.Substring(13)); // trim off what will become redundant "WARNING" label. m_state = WfdState.DontKnow; break; } else if (s.StartsWith("*** ERROR: ", StringComparison.OrdinalIgnoreCase)) { s = s.Substring(11); // trim off what will become redundant "ERROR" label. var dpe = new DbgProviderException(s, "ErrorDuringUnassemble", ErrorCategory.ReadError); try { throw dpe; } catch (Exception) { } // give it a stack. m_pipeline.WriteError(dpe); m_state = WfdState.DontKnow; break; } else if (s.StartsWith("No code found, aborting", StringComparison.OrdinalIgnoreCase)) { var dpe = new DbgProviderException(s, "NoCodeFound", ErrorCategory.ReadError); try { throw dpe; } catch (Exception) { } // give it a stack. m_pipeline.WriteError(dpe); m_state = WfdState.DontKnow; // actually, we should be done now. break; } else if ((s.Length > 0) && (s[s.Length - 1] == ':')) { // Looks like a block ID... m_state = WfdState.ExpectingBlockId; AddLine(s); } else if (String.IsNullOrEmpty(s)) { m_state = WfdState.ExpectingBlockId; m_currentBlockId = null; } else { m_state = WfdState.ExpectingInstructionOrBlankLine; AddLine(s); } break; default: Util.Fail("Invalid parse state."); throw new Exception("Invalid parse state."); } } // end AddLine()
} // end AddSourceFile() /// <summary> /// Re-runs the list of registered source files, after clearing the internal /// list of registered source files. /// </summary> /// <remarks> /// It is assumed that when a script runs, it calls some command that causes /// AddSourceFile to be called, thereby re-registering itself. If a script /// produces an error, however, it is kept in the list of source files, so that /// a user can fix the error and call this again without re-registering the /// script. /// /// If a script in appendScripts is already in the list, no change is made (the /// script does not get added again to the end of the list, or moved). If a /// script in prependScripts is already in the list, it gets moved from its /// original position to the front. /// </remarks> public void Reload(CommandInvocationIntrinsics invokeCommand, IList <string> appendScripts, IList <string> prependScripts, string dataDisplayName, // for verbose messages IPipelineCallback pipe) { if (null == pipe) { throw new ArgumentNullException("pipe"); } pipe.WriteVerbose("Dumping old {0}...", dataDisplayName); m_DumpContent(); if (null != appendScripts) { foreach (var newScript in appendScripts) { // Unlike the prepend case, here we don't change the position of the // script in the list if it's already in it. if ((null != newScript) && m_sourceFilesSet.Add(newScript)) { pipe.WriteVerbose("Appending script: {0}", newScript); m_sourceFiles.AddLast(newScript); } } } if (null != prependScripts) { foreach (var newScript in prependScripts) { if (null != newScript) { if (m_sourceFilesSet.Remove(newScript)) { pipe.WriteVerbose("Prepending (moving) script: {0}", newScript); m_sourceFiles.Remove(newScript); } else { pipe.WriteVerbose("Prepending script: {0}", newScript); } m_sourceFiles.AddFirst(newScript); } } } // It's possible that there's conditional logic in the scripts that causes // different scripts to run, so we'd better clear out the existing source // files list (after making a copy). var oldSourceFiles = m_sourceFiles.ToArray(); m_sourceFiles.Clear(); m_sourceFilesSet.Clear(); foreach (string sourceScript in oldSourceFiles) { try { // If there are errors parsing the file, then it won't be run, and if // it doesn't get run, something won't call AddSourceFile, and if it // doesn't call AddSourceFile, we won't save the script file to run // again next time someone calls Reload. So we'll save the script name // in the "files to run" /now/, instead of later. pipe.WriteVerbose("Adding {0} from: {1}", dataDisplayName, sourceScript); if (AddSourceFile(sourceScript)) { ScriptBlockAst ast = InvokeScriptCommand.LoadScript(sourceScript); // TODO: should I do anything with any output? InvokeScriptCommand.InvokeScript(invokeCommand, ast.GetScriptBlock(), true); } else { // I don't think it should be possible to get here. Util.Fail("How did we get here?"); } } catch (DbgProviderException dpe) { pipe.WriteError(dpe.ErrorRecord); } catch (RuntimeException re) { pipe.WriteError(re.ErrorRecord); } } } // end Reload()