using System; using System.Collections.Specialized; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Microsoft.Win32; using Cosmos.Build.Common; using Cosmos.Debug.Common; namespace Cosmos.Debug.VSDebugEngine.Host { /// This class handles interactions with the Bochs emulation environment. public partial class Bochs: Base { /// The emulator process once started. private static Process _bochsProcess; /// The configuration file to be used when launching the Bochs virtual machine. private FileInfo _bochsConfigurationFile; private bool _useDebugVersion; /// Instanciation occurs when debugging engine is invoked to launch the process in suspended /// mode. Bochs process will eventually be launched later when debugging engine is instructed to /// Attach to the debugged process. public Bochs(NameValueCollection aParams, bool aUseGDB, FileInfo configurationFile) : base(aParams, aUseGDB) { if (null == configurationFile) { throw new ArgumentNullException("configurationFile"); } /*if (!configurationFile.Exists) { InitializeKeyValues(); }*/ InitializeKeyValues(); GenerateConfiguration(configurationFile.FullName); _bochsConfigurationFile = configurationFile; bool parseSucceeded = bool.TryParse(aParams[BuildProperties.EnableBochsDebugString], out _useDebugVersion); return; } /// Fix the content of the configuration file, replacing each of the symbolic variable occurence /// with its associated value. /// A set of key/value pairs where the key is the name of a variable. The value is /// used for variable replacement. Variables are case sensistive. internal void FixBochsConfiguration(KeyValuePair[] symbols) { if ((null == symbols) || (0 == symbols.Length)) { return; } string content; using (StreamReader reader = new StreamReader(File.Open(_bochsConfigurationFile.FullName, FileMode.Open, FileAccess.Read))) { content = reader.ReadToEnd(); } foreach (KeyValuePair pair in symbols) { string variableName = string.Format("$({0})", pair.Key); content.Replace(variableName, pair.Value); } using (StreamWriter writer = new StreamWriter(File.Open(_bochsConfigurationFile.FullName, FileMode.Create, FileAccess.Write))) { writer.Write(content); } } /// Initialize and start the Bochs process. public override void Start() { _bochsProcess = new Process(); ProcessStartInfo _bochsStartInfo = _bochsProcess.StartInfo; _bochsStartInfo.FileName = (_useDebugVersion && BochsSupport.BochsDebugExe.Exists) ? BochsSupport.BochsDebugExe.FullName : BochsSupport.BochsExe.FullName; // Start Bochs without displaying the configuration interface (-q) and using the specified // configuration file (-f). The user is intended to edit the configuration file coming with // the Cosmos project whenever she wants to modify the environment. _bochsStartInfo.Arguments = string.Format("-q -f \"{0}\"", _bochsConfigurationFile.FullName); _bochsStartInfo.WorkingDirectory = _bochsConfigurationFile.Directory.FullName; _bochsStartInfo.UseShellExecute = false; // Register for process completion event so that we can funnel it to any code that // subscribed to this event in our base class. _bochsProcess.EnableRaisingEvents = true; _bochsProcess.Exited += ExitCallback; _bochsProcess.Start(); return; } private void ExitCallback(object sender, EventArgs e) { if (null != OnShutDown) { try { OnShutDown(sender, e); } catch { } } } public override void Stop() { if (null != _bochsProcess) { try { _bochsProcess.Kill(); } catch { } } CleanUp(); } private void CleanUp() { OnShutDown(this, null); _bochsProcess.Exited -= ExitCallback; // TODO BlueSkeye : What kind of garbage may Bochs have left for us to clean ? } } }