
* The `Breakpoint' class

The `Breakpoint' class is an abstract class which the user interface must derive.  There's
also a `SimpleBreakpoint' class if you "just want a breakpoint".

This class is fully serializable and holds all the user's settings for this breakpoint.
The GUI should save it to disk to store the user's breakpoint settings.

See the inline documentation in class/Breakpoint.cs for more information.

* Inserting Breakpoints

To insert a new breakpoint, the first thing you need to do is creating a new `Breakpoint'
instance; you may use the `SimpleBreakpoint' if you just need a breakpoint and nothing
more.

A new breakpoint is created by calling DebuggerBackend.InsertBreakpoint().  This method is
overloaded to allow you to insert the breakpoint either by method name or source file
name.

In both cases, DebuggerBackend.InsertBreakpoint() is a low-level function and very
inconvenient for the user, it's indendet to be called from a GUI's breakpoint manager
after the GUI already searched the breakpoint.

* Findihg the breakpoint location

There are two ways to find the location where you want to insert the breakpoint: either by
method name or by source file / line number.

First of all, you must find out in which method you want to insert the breakpoint and get
the method's SourceMethodInfo.  You can either search it by method name or by source
location - Module.FindMethod will do this for you.

Internally, each Module has a hashtable which maps a fully qualified method name to its
SourceMethodInfo; this will be used when searching by method name.

To search by source file and line number, you need to find the source file's SourceInfo
and then search the method in it.  There's Module.FindMethod(string,int) which'll do this
for you.  Internally, this'll first search the file, then compute the file's method list
and search the method in this list.

* Ok, so now you have the SourceMethodInfo

To actually insert the breakpoint, you need to have an IMethod instance which contains the
method's machine address and its line number table.  However, the lifetime of this
information is limited to the currently running target and it'd also consume too much
memory to hold it in memory all the time.

That's what SourceMethodInfo is used for - it's a small handle to an IMethod which is so
small that it can be kept in memory and which can also persist across multiple invocations
of the target.

However, from the user interface's perspective, this is all you need to insert the
breakpoint - the backend will take care of the rest.

* Internally - Mono / C#

When inserting a breakpoint for a managed method, the backend first checks whether the
method has already been JITed.  If so, SourceMethodInfo.IsLoaded will be true and we can
use SourceMethodInfo.Method to get the method's IMethod.  Once we have an IMethod, we can
get it's StartAddress or search the address of a source line in the line number table by
using IMethod.Lookup(int).

If not, the debugger calls SourceMethodInfo.RegisterLoadHandler() to register a delegate
to be invoked after the method is JITed (internally, the backend calls mono_insert_breakpoint()
in the target's JIT, so the target will hit a breakpoint in the method's breakpoint
trampoline immediately after it's JITed).

The delegate is invoked after adding the newly JITed method to the debugger's symbol
tables - so we'll have the method's IMethod and can actually insert the breakpoint.

When inserting a breakpoint by source line, the mechanism is almost the same, we use
SourceMethodInfo.RegisterLoadHandler() to register the delegate, but the delegate must
search the address in the method's line number table.

Internally, the backend will only register the breakpoint once with the target's JIT and
call all the load handler's when it's JITed.

