open executable...
0:000> sxe ld clr
0:000> g
0:000> .loadby sos clr
0:000> sxe ld clr
0:000> .loadby sos clr
0:000> g 这个很重要,jit
0:000> !clrstack
0:000> !help bpmd
!BPMD [-nofuturemodule] <module name> <method name> [<il offset>]
!BPMD <source file name>:<line number>
!BPMD -md <MethodDesc>
!BPMD -list
!BPMD -clear <pending breakpoint number>
!BPMD -clearall
!BPMD provides managed breakpoint support. If it can resolve the method name
to a loaded, jitted or ngen’d function it will create a breakpoint with “bp”.
If not then either the module that contains the method hasn’t been loaded yet
or the module is loaded, but the function is not jitted yet. In these cases,
!bpmd asks the Windows Debugger to receive CLR Notifications, and waits to
receive news of module loads and JITs, at which time it will try to resolve
the function to a breakpoint. -nofuturemodule can be used to suppress
creating a breakpoint against a module that has not yet been loaded.
Management of the list of pending breakpoints can be done via !BPMD -list,
!BPMD -clear, and !BPMD -clearall commands. !BPMD -list generates a list of
all of the pending breakpoints. If the pending breakpoint has a non-zero
module id, then that pending breakpoint is specific to function in that
particular loaded module. If the pending breakpoint has a zero module id, then
the breakpoint applies to modules that have not yet been loaded. Use
!BPMD -clear or !BPMD -clearall to remove pending breakpoints from the list.
This brings up a good question: “I want to set a breakpoint on the main
method of my application. How can I do this?”
1) If you know the full path to SOS, use this command and skip to step 6
.load <the full path to sos.dll>
2) If you don't know the full path to sos, its usually next to clr.dll
You can wait for clr to load and then find it.
Start the debugger and type:
sxe -c "" clrn
3) g
4) You'll get the following notification from the debugger:
"CLR notification: module 'mscorlib' loaded"
5) Now you can load SOS. Type
.loadby sos clr
6) Add the breakpoint with command such as:
!bpmd myapp.exe MyApp.Main
7) g
8) You will stop at the start of MyApp.Main. If you type "bl" you will
see the breakpoint listed.
You can specify breakpoints by file and line number if:
a) You have some version of .Net Framework installed on your machine. Any OS from
Vista onwards should have .Net Framework installed by default.
b) You have PDBs for the managed modules that need breakpoints, and your symbol
path points to those PDBs.
This is often easier than module and method name syntax. For example:
!bpmd Demo.cs:15
To correctly specify explicitly implemented methods make sure to retrieve the
method name from the metadata, or from the output of the “!dumpmt -md” command.
For example:
public interface I1
{
void M1();
}
public class ExplicitItfImpl : I1
{
...
void I1.M1() // this method's name is 'I1.M1'
{ ... }
}
!bpmd myapp.exe ExplicitItfImpl.I1.M1
!BPMD works equally well with generic types. Adding a breakpoint on a generic
type sets breakpoints on all already JIT-ted generic methods and sets a pending
breakpoint for any instantiation that will be JIT-ted in the future.
Example for generics:
Given the following two classes:
class G3<T1, T2, T3>
{
...
public void F(T1 p1, T2 p2, T3 p3)
{ ... }
}
public class G1<T> {
// static method
static public void G<W>(W w)
{ ... }
}
One would issue the following commands to set breapoints on G3.F() and
G1.G():
!bpmd myapp.exe G3`3.F
!bpmd myapp.exe G1`1.G
And for explicitly implemented methods on generic interfaces:
public interface IT1
{
void M1(T t);
}
public class ExplicitItfImpl<U> : IT1<U>
{
...
void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
{ ... }
}
!bpmd bpmd.exe ExplicitItfImpl`1.IT1<U>.M1
Additional examples:
If IT1 and ExplicitItfImpl are types declared inside another class,
Outer, the bpmd command would become:
!bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
(note that the fully qualified type name for ExplicitItfImpl became
Outer+ExplicitItfImpl, using the '+' separator, while the method name
is Outer.IT1<U>.M1, using a '.' as the separator)
Furthermore, if the Outer class resides in a namespace, NS, the bpmd
command to use becomes:
!bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
!BPMD does not accept offsets nor parameters in the method name. You can add
an IL offset as an optional parameter seperate from the name. If there are overloaded
methods, !bpmd will set a breakpoint for all of them.
In the case of hosted environments such as SQL, the module name may be
complex, like ‘price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’.
For this case, just be sure to surround the module name with single quotes,
like:
!bpmd ‘price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ Price.M2
0:000> !help name2ee
!Name2EE
!Name2EE !
This function allows you to turn a class name into a MethodTable and EEClass.
It turns a method name into a MethodDesc. Here is an example for a method:
0:000> !name2ee unittest.exe MainClass.Main
Module: 001caa38
Token: 0x0600000d
MethodDesc: 00902f40
Name: MainClass.Main()
JITTED Code Address: 03ef00b8
and for a class:
0:000> !name2ee unittest!MainClass
Module: 001caa38
Token: 0x02000005
MethodTable: 009032d8
EEClass: 03ee1424
Name: MainClass
The module you are “browsing” with Name2EE needs to be loaded in the process.
To get a type name exactly right, first browse the module with ILDASM. You
can also pass * as the to search all loaded managed modules.
can also be the debugger’s name for a module, such as
mscorlib or image00400000.
The Windows Debugger syntax of ! is also supported. You can
use an asterisk on the left of the !, but the type on the right side needs
to be fully qualified.
If you are looking for a way to display a static field of a class (and you
don’t have an instance of the class, so !dumpobj won’t help you), note that
once you have the EEClass, you can run !DumpClass, which will display the
value of all static fields.
There is yet one more way to specify a module name. In the case of modules
loaded from an assembly store (such as a SQL db) rather than disk, the
module name will look like this:
price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
For this kind of module, simply use price as the module name:
0:044> !name2ee price Price
Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
Token: 0x02000002
MethodTable: 11a47ae0
EEClass: 11a538c8
Name: Price
Where are we getting these module names from? Run !DumpDomain to see a list of
all loaded modules in all domains. And remember that you can browse all the
types in a module with !DumpModule -mt .