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 ?
}
}
}