Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

998 lines (810 sloc) 23.326 kb
using System;
using System.Text;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Remoting;
using System.Runtime.Serialization;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using Mono.Debugger;
using Mono.Debugger.Languages;
using EE=Mono.Debugger.ExpressionEvaluator;
namespace Mono.Debugger.Frontend
{
public class Interpreter : DebuggerMarshalByRefObject, IInterruptionHandler, IDisposable
{
DebuggerConfiguration config;
DebuggerSession session;
DebuggerEngine engine;
SourceFileFactory source_factory;
Debugger debugger;
Process main_process;
Process current_process;
Hashtable styles;
StyleBase current_style;
bool is_interactive;
bool is_script;
int exit_code = 0;
int interrupt_level;
ExpressionParser parser;
ManualResetEvent interrupt_event;
ManualResetEvent process_event;
Thread current_thread;
internal static readonly string DirectorySeparatorStr;
static Interpreter ()
{
// FIXME: Why isn't this public in System.IO.Path ?
DirectorySeparatorStr = Path.DirectorySeparatorChar.ToString ();
}
public Interpreter (bool is_interactive, DebuggerConfiguration config,
DebuggerOptions options)
{
this.config = config;
this.is_interactive = is_interactive;
this.is_script = options.IsScript;
this.parser = new ExpressionParser (this);
this.session = new DebuggerSession (config, options, "main", parser);
this.engine = new DebuggerEngine (this);
parser.Session = session;
source_factory = new SourceFileFactory ();
interrupt_event = new ManualResetEvent (false);
process_event = new ManualResetEvent (false);
styles = new Hashtable ();
styles.Add ("cli", new StyleCLI (this));
styles.Add ("emacs", new StyleEmacs (this));
current_style = (StyleBase) styles ["cli"];
}
public void Exit ()
{
try {
Dispose ();
} catch (Exception ex) {
Console.WriteLine (ex);
} finally {
Environment.Exit (exit_code);
}
}
public StyleBase Style {
get { return current_style; }
set {
current_style = value;
current_style.Reset ();
}
}
public DebuggerConfiguration DebuggerConfiguration {
get { return config; }
}
public DebuggerEngine DebuggerEngine {
get { return engine; }
}
public SourceFileFactory SourceFileFactory {
get { return source_factory; }
}
public Process CurrentProcess {
get {
if (current_process == null)
throw new TargetException (TargetError.NoTarget);
return current_process;
}
set { current_process = value; }
}
public bool HasCurrentProcess {
get { return current_process != null; }
}
public DebuggerSession Session {
get {
if (session == null)
throw new TargetException (TargetError.NoTarget);
return session;
}
}
public StyleBase GetStyle (string name)
{
StyleBase style = (StyleBase) styles [name];
if (style == null)
throw new ScriptingException (
"No such user interface: `{0}'", name);
return style;
}
public string[] GetStyleNames ()
{
string[] names = new string[styles.Keys.Count];
styles.Keys.CopyTo (names, 0);
return names;
}
public ExpressionParser ExpressionParser {
get { return parser; }
}
public bool IsInteractive {
get { return is_interactive; }
set { is_interactive = value; }
}
public bool IsScript {
get { return is_script; }
set { is_script = value; }
}
public DebuggerOptions Options {
get { return session.Options; }
}
public int ExitCode {
get { return exit_code; }
set { exit_code = value; }
}
public void Abort ()
{
Print ("Caught fatal error while running non-interactively; exiting!");
Environment.Exit (-1);
}
public void Error (string message)
{
Report.Error ("ERROR: {0}", message);
}
public void Error (string format, params object[] args)
{
Error (String.Format (format, args));
}
public void Error (ScriptingException ex)
{
Error (ex.Message);
}
public void Error (TargetException ex)
{
Error (ex.Message);
}
public virtual void Print (string message)
{
Report.Print ("{0}\n", message);
}
public void Print (string format, params object[] args)
{
Print (String.Format (format, args));
}
public void Print (object obj)
{
Print (obj.ToString ());
}
public bool Query (string prompt) {
Report.Print (prompt);
Report.Print (" (y or n) ");
string result = Report.ReadLine ();
return (result == "y") || (result == "yes");
}
public void PrintInstruction (AssemblerLine line)
{
if (line.Label != null)
Print ("{0}:", line.Label);
Print ("{0:11x}\t{1}", line.Address, line.Text);
}
public TargetFunctionType QueryMethod (TargetFunctionType[] methods)
{
Report.Print ("More than one method matches your query:\n");
ArrayList list = new ArrayList ();
foreach (TargetFunctionType method in methods) {
list.Add (method);
Report.Print ("{0,4} {1}\n", list.Count, method.Name);
}
Report.Print ("Select a method or 0 to abort: ");
string result = Report.ReadLine ();
uint index;
try {
index = UInt32.Parse (result);
} catch {
Report.Print ("Invalid number.");
return null;
}
if (index == 0)
return null;
if (index > list.Count) {
Report.Print ("No such method.");
return null;
}
return (TargetFunctionType) list [(int) index];
}
public bool HasTarget {
get {
return (debugger != null) && debugger.HasTarget;
}
}
public Process Start ()
{
if ((debugger != null) || (main_process != null))
throw new TargetException (TargetError.AlreadyHaveTarget);
if (!IsScript)
Print ("Starting program: {0} {1}", Options.File,
String.Join (" ", Options.InferiorArgs));
try {
debugger = new Debugger (config);
new InterpreterEventSink (this, debugger);
CommandResult result;
current_process = main_process = debugger.Run (session, out result);
current_thread = current_process.MainThread;
Wait (result);
return current_process;
} catch (TargetException) {
debugger.Dispose ();
debugger = null;
throw;
}
}
public Process Attach (int pid)
{
if ((debugger != null) || (main_process != null))
throw new TargetException (TargetError.AlreadyHaveTarget);
if (!IsScript)
Print ("Attaching to {0}", pid);
try {
debugger = new Debugger (config);
new InterpreterEventSink (this, debugger);
CommandResult result;
current_process = main_process = debugger.Attach (session, pid, out result);
current_thread = current_process.MainThread;
Wait (result);
return current_process;
} catch (TargetException) {
debugger.Dispose ();
debugger = null;
throw;
}
}
#if DISABLED
public Process OpenCoreFile (string core_file)
{
if ((debugger != null) || (main_process != null))
throw new TargetException (TargetError.AlreadyHaveTarget);
Console.WriteLine ("Loading core file {0}", core_file);
try {
debugger = new Debugger (config);
new InterpreterEventSink (this, debugger);
Thread[] threads;
current_process = main_process = debugger.OpenCoreFile (
session, core_file, out threads);
current_thread = current_process.MainThread;
return current_process;
} catch (TargetException) {
debugger.Dispose ();
debugger = null;
throw;
}
}
#endif
public void SaveSession (Stream stream)
{
session.SaveSession (stream);
}
public Process LoadSession (Stream stream)
{
if ((debugger != null) || (main_process != null))
throw new TargetException (TargetError.AlreadyHaveTarget);
try {
debugger = new Debugger (config);
parser = new ExpressionParser (this);
session = new DebuggerSession (config, stream, parser);
parser.Session = session;
new InterpreterEventSink (this, debugger);
CommandResult result;
current_process = main_process = debugger.Run (session, out result);
current_thread = current_process.MainThread;
Wait (result);
return current_process;
} catch (TargetException ex) {
Console.WriteLine ("Got a TargetException during LoadSession: {0}", ex);
debugger.Dispose ();
debugger = null;
throw;
} catch (Exception ex) {
Console.WriteLine ("Got an Exception during LoadSession: {0}", ex);
debugger.Dispose ();
debugger = null;
throw;
}
}
public bool Wait (CommandResult result)
{
if (result == null)
return true;
ClearInterrupt ();
WaitHandle[] handles = new WaitHandle [2];
handles [0] = interrupt_event;
handles [1] = result.CompletedEvent;
int ret = WaitHandle.WaitAny (handles);
if (ret == 0) {
result.Abort ();
result.CompletedEvent.WaitOne ();
return false;
}
if (result.Result is Exception)
throw (Exception) result.Result;
return true;
}
public int Interrupt ()
{
interrupt_event.Set ();
return ++interrupt_level;
}
public void ClearInterrupt ()
{
interrupt_level = 0;
interrupt_event.Reset ();
}
WaitHandle IInterruptionHandler.InterruptionEvent {
get { return interrupt_event; }
}
bool IInterruptionHandler.CheckInterruption ()
{
return interrupt_level > 0;
}
public void ShowBreakpoints ()
{
Event[] events = Session.Events;
if (events.Length == 0) {
Print ("No breakpoints or catchpoints.");
return;
}
Print ("Breakpoints:");
Print ("{0,3} {1,6} {2,3} {3,4} {4,12} {5}", "Id", "Type", "En", "Act", "ThreadGroup", "What");
foreach (Event handle in events) {
string type;
if (handle is ExceptionCatchPoint)
type = "catch";
else
type = "break";
Print ("{0,3} {1,6} {2,3} {3,4} {4,12} {5}",
handle.Index, type,
handle.IsEnabled ? "y" : "n",
handle.IsActivated ? "y" : "n",
handle.ThreadGroup != null ? handle.ThreadGroup.Name : "global",
handle.Name);
}
}
public Event GetEvent (int index)
{
Event handle = Session.GetEvent (index);
if (handle == null)
throw new ScriptingException ("No such breakpoint/catchpoint.");
return handle;
}
protected virtual void OnThreadCreated (Thread thread)
{
process_event.Set ();
if ((DebuggerConfiguration.UserNotifications & DebuggerConfiguration.UserNotificationType.Threads) != 0)
Print ("Process #{0} created new thread @{1}.",
thread.Process.ID, thread.ID);
}
protected virtual void OnThreadExited (Thread thread)
{
if ((DebuggerConfiguration.UserNotifications & DebuggerConfiguration.UserNotificationType.Threads) != 0)
Print ("Thread @{0} exited.", thread.ID);
if (thread == current_thread)
current_thread = null;
}
protected virtual void OnMainProcessCreated (Process process)
{
new ProcessEventSink (this, process);
}
protected virtual void OnProcessReachedMain (Process process)
{ }
protected virtual void OnProcessCreated (Process process)
{
process_event.Set ();
new ProcessEventSink (this, process);
Print ("Created new process #{0}.", process.ID);
if (current_process == null) {
current_process = process;
current_thread = process.MainThread;
}
}
protected virtual void OnProcessExited (Process process)
{
Print ("Process #{0} exited.", process.ID);
if (process == main_process) {
current_process = main_process = null;
current_thread = null;
} else if (process == current_process) {
current_process = main_process;
current_thread = main_process.MainThread;
}
}
protected virtual void OnProcessExecd (Process process)
{
Print ("Process #{0} exec()'d: {1}", process.ID,
PrintCommandLineArgs (process));
}
protected virtual void OnTargetEvent (Thread thread, TargetEventArgs args)
{
if ((args.Type != TargetEventType.TargetSignaled) &&
(args.Type != TargetEventType.TargetExited) &&
(args.Type != TargetEventType.TargetInterrupted))
CurrentThread = thread;
Style.TargetEvent (thread, args);
}
protected virtual void OnTargetOutput (bool is_stderr, string line)
{
if (!IsScript) {
if (is_stderr)
Report.Print ("{0}", line);
else
Report.Print ("{0}", line);
}
}
protected virtual void OnTargetExited ()
{
debugger = null;
main_process = current_process = null;
current_thread = null;
Print ("Target exited.");
}
public Thread CurrentThread {
get {
if (current_thread == null)
throw new TargetException (TargetError.NoTarget);
return current_thread;
}
set {
current_thread = value;
current_process = value.Process;
}
}
public bool HasCurrentThread {
get { return current_thread != null; }
}
public Process GetProcess (int number)
{
if (number == -1)
return CurrentProcess;
foreach (Process process in Processes) {
if (process.ID == number)
return process;
}
throw new ScriptingException ("No such process: {0}", number);
}
public Thread GetThread (int number)
{
if (number == -1)
return CurrentThread;
foreach (Process process in Processes) {
foreach (Thread thread in process.GetThreads ())
if (thread.ID == number)
return thread;
}
throw new ScriptingException ("No such thread: {0}", number);
}
public Thread[] GetThreads (int[] indices)
{
Thread[] retval = new Thread [indices.Length];
for (int i = 0; i < indices.Length; i++)
retval [i] = GetThread (indices [i]);
return retval;
}
public void ShowThreadGroups ()
{
foreach (ThreadGroup group in Session.ThreadGroups) {
if (group.Name.StartsWith ("@"))
continue;
StringBuilder ids = new StringBuilder ();
foreach (int thread in group.Threads) {
ids.Append (" @");
ids.Append (thread);
}
Print ("{0}:{1}", group.Name, ids.ToString ());
}
}
public void CreateThreadGroup (string name)
{
if (Session.ThreadGroupExists (name))
throw new ScriptingException ("A thread group with that name already exists.");
Session.CreateThreadGroup (name);
}
public void DeleteThreadGroup (string name)
{
if (!Session.ThreadGroupExists (name))
throw new ScriptingException ("No such thread group.");
Session.DeleteThreadGroup (name);
}
public ThreadGroup GetThreadGroup (string name, bool writable)
{
if (name == null)
name = "main";
else if (name == "global")
return ThreadGroup.Global;
if (name.StartsWith ("@"))
throw new ScriptingException ("No such thread group.");
if (!Session.ThreadGroupExists (name))
throw new ScriptingException ("No such thread group.");
ThreadGroup group = Session.CreateThreadGroup (name);
if (writable && group.IsSystem)
throw new ScriptingException ("Cannot modify system-created thread group.");
return group;
}
public void AddToThreadGroup (string name, Thread[] threads)
{
ThreadGroup group = GetThreadGroup (name, true);
foreach (Thread thread in threads)
group.AddThread (thread.ID);
}
public void RemoveFromThreadGroup (string name, Thread[] threads)
{
ThreadGroup group = GetThreadGroup (name, true);
foreach (Thread thread in threads)
group.RemoveThread (thread.ID);
}
public int InsertExceptionCatchPoint (Thread target, ThreadGroup group,
TargetType exception, bool unhandled)
{
Event handle = target.Process.Session.InsertExceptionCatchPoint (
target, group, exception, unhandled);
return handle.Index;
}
public int InsertHardwareWatchPoint (Thread target, TargetAddress address)
{
Event handle = target.Process.Session.InsertHardwareWatchPoint (
target, address, HardwareWatchType.WatchWrite);
return handle.Index;
}
public void Kill ()
{
if (debugger != null) {
debugger.Kill ();
debugger = null;
}
}
public void Kill (Process process)
{
if (process == main_process)
Kill ();
else
process.Kill ();
}
public void Detach ()
{
debugger.Detach ();
}
public void Detach (Process process)
{
if (process == main_process)
Detach ();
else
process.Detach ();
}
public Module[] GetModules (int[] indices)
{
List<Module> retval = new List<Module> ();
Module[] modules = CurrentProcess.Modules;
foreach (int index in indices) {
bool found = false;
for (int i = 0; i < modules.Length; i++) {
if (modules [i].ID == index) {
retval.Add (modules [i]);
found = true;
break;
}
}
if (!found)
throw new ScriptingException ("No such module {0}.", index);
}
return retval.ToArray ();
}
public SourceFile[] GetSources (int[] indices)
{
Hashtable source_hash = new Hashtable ();
Module[] modules = CurrentProcess.Modules;
foreach (Module module in modules) {
if (!module.SymbolsLoaded)
continue;
foreach (SourceFile source in module.Sources)
source_hash.Add (source.ID, source);
}
int pos = 0;
SourceFile[] retval = new SourceFile [indices.Length];
foreach (int index in indices) {
SourceFile source = (SourceFile) source_hash [index];
if (source == null)
throw new ScriptingException (
"No such source file: {0}", index);
retval [pos++] = source;
}
return retval;
}
public SourceBuffer ReadFile (string filename)
{
return source_factory.FindFile (filename);
}
public void ModuleOperations (Module[] modules, ModuleOperation[] operations)
{
foreach (Module module in modules) {
foreach (ModuleOperation operation in operations) {
switch (operation) {
case ModuleOperation.Ignore:
module.LoadSymbols = false;
break;
case ModuleOperation.UnIgnore:
module.LoadSymbols = true;
break;
case ModuleOperation.Step:
module.StepInto = true;
break;
case ModuleOperation.DontStep:
module.StepInto = false;
break;
default:
throw new InternalError ();
}
}
}
}
public Process[] Processes {
get {
if (debugger == null)
throw new TargetException (TargetError.NoTarget);
return debugger.Processes;
}
}
public string PrintCommandLineArgs (Process process)
{
StringBuilder sb = new StringBuilder ();
string[] args = process.CommandLineArguments;
int start = 0;
if ((args.Length > 1) && (args [0] == BuildInfo.mono)) {
if (args [1] == "--inside-mdb")
start = 2;
else
start = 1;
}
for (int i = start; i < args.Length; i++) {
if (i > start)
sb.Append (" ");
sb.Append (args [i]);
}
return sb.ToString ();
}
public string PrintProcess (Process process)
{
string command_line = PrintCommandLineArgs (process);
if (command_line.Length > 70) {
command_line = command_line.Substring (0, 70);
command_line += " ...";
}
return String.Format ("#{0} ({1}:{2})", process.ID,
process.MainThread.PID, command_line);
}
public void ShowDisplays (StackFrame frame)
{
ScriptingContext context = new ScriptingContext (this);
context.CurrentFrame = frame;
foreach (Display d in Session.Displays)
context.ShowDisplay (d);
}
internal CommandLineInterpreter CLI {
get; set;
}
protected virtual void OnEnterNestedBreakState (Thread thread)
{
if (CLI != null)
CLI.EnterNestedBreakState ();
}
protected void OnLeaveNestedBreakState (Thread thread)
{
if (CLI != null)
CLI.LeaveNestedBreakState ();
}
//
// IDisposable
//
private bool disposed = false;
private void Dispose (bool disposing)
{
// Check to see if Dispose has already been called.
lock (this) {
if (disposed)
return;
disposed = true;
}
// If this is a call to Dispose, dispose all managed resources.
if (disposing) {
if (debugger != null) {
debugger.Kill ();
debugger = null;
}
}
}
public void Dispose ()
{
Dispose (true);
// Take yourself off the Finalization queue
GC.SuppressFinalize (this);
}
~Interpreter ()
{
Dispose (false);
}
protected class InterpreterEventSink : DebuggerMarshalByRefObject
{
Interpreter interpreter;
public InterpreterEventSink (Interpreter interpreter, Debugger debugger)
{
this.interpreter = interpreter;
debugger.TargetExitedEvent += target_exited;
debugger.ThreadCreatedEvent += thread_created;
debugger.ManagedThreadCreatedEvent += managed_thread_created;
debugger.ThreadExitedEvent += thread_exited;
debugger.MainProcessCreatedEvent += main_process_created;
debugger.ProcessReachedMainEvent += process_reached_main;
debugger.ProcessCreatedEvent += process_created;
debugger.ProcessExitedEvent += process_exited;
debugger.ProcessExecdEvent += process_execd;
debugger.TargetEvent += target_event;
debugger.EnterNestedBreakStateEvent +=
delegate (Debugger unused, Thread thread) {
interpreter.OnEnterNestedBreakState (thread);
};
debugger.LeaveNestedBreakStateEvent +=
delegate (Debugger unused, Thread thread) {
interpreter.OnLeaveNestedBreakState (thread);
};
}
public void target_event (Thread thread, TargetEventArgs args)
{
if (((thread.ThreadFlags & Thread.Flags.Daemon) != 0) &&
((args.Type == TargetEventType.TargetExited) ||
(args.Type == TargetEventType.TargetSignaled)))
return;
interpreter.OnTargetEvent (thread, args);
}
public void thread_created (Debugger debugger, Thread thread)
{
if (!thread.Process.IsManaged ||
((thread.ThreadFlags & Thread.Flags.Daemon) == 0))
interpreter.OnThreadCreated (thread);
}
public void managed_thread_created (Debugger debugger, Thread thread)
{
interpreter.OnThreadCreated (thread);
}
public void thread_exited (Debugger debugger, Thread thread)
{
if ((thread.ThreadFlags & Thread.Flags.Daemon) == 0)
interpreter.OnThreadExited (thread);
}
public void main_process_created (Debugger debugger, Process process)
{
interpreter.OnMainProcessCreated (process);
}
public void process_reached_main (Debugger debugger, Process process)
{
interpreter.OnProcessReachedMain (process);
}
public void process_created (Debugger debugger, Process process)
{
interpreter.OnProcessCreated (process);
}
public void process_exited (Debugger debugger, Process process)
{
interpreter.OnProcessExited (process);
}
public void process_execd (Debugger debugger, Process process)
{
interpreter.OnProcessExecd (process);
}
public void target_exited (Debugger debugger)
{
interpreter.OnTargetExited ();
}
}
protected class ProcessEventSink : DebuggerMarshalByRefObject
{
Interpreter interpreter;
public ProcessEventSink (Interpreter interpreter, Process process)
{
this.interpreter = interpreter;
process.TargetOutputEvent += target_output;
}
public void target_output (bool is_stderr, string line)
{
interpreter.OnTargetOutput (is_stderr, line);
}
}
}
}
Jump to Line
Something went wrong with that request. Please try again.