I'm interested in viewing the actual x86 assembly output by a C# program (not the CLR bytecode instructions). Is there a good way to do this?
While debugging your application in Visual Studio, you can right-click on a code where you have stopped (using breakpoint) and click "Go to Disassembly". You can debug through native instructions.
As for doing that with *.exe files on disk, maybe you could use NGen to generate native output and then disassemble it (although I never tried that, so I can't guarantee that it will work).
Here are some sample opcodes from simple arithmetic operation that was written in c#:
int x = 5;
mov dword ptr [ebp-40h],5
int y = 6;
mov dword ptr [ebp-44h],6
int z = x + y;
mov eax,dword ptr [ebp-40h]
add eax,dword ptr [ebp-44h]
mov dword ptr [ebp-48h],eax
As #IvanDanilov answered, you can use WinDbg and SOS. I am answering separately to provide a walk-through.
In this example, I want to view the disassembly of the AreEqual() method from:
using System;
namespace TestArrayCompare
{
class Program
{
static bool AreEqual(byte[] a1, byte[] a2)
{
bool result = true;
for (int i = 0; i < a1.Length; ++i)
{
if (a1[i] != a2[i])
result = false;
}
return result;
}
static void Main(string[] args)
{
byte[] a1 = new byte[100];
byte[] a2 = new byte[100];
if (AreEqual(a1, a2))
{
Console.WriteLine("`a1' equals `a2'.");
}
else
{
Console.WriteLine("`a1' does not equal `a2'.");
}
}
}
}
Steps:
Open WinDbg. From the File menu, select "Open Executable...". Browse to the location of the EXE (in my case, C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe).
Add the directory containing the PDB file to the symbol path. For example:
.sympath "C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release"
In WinDbg's Command window, set a breakpoint when clr.dll is loaded via:
sxe ld:clr
Continue by running the 'Go' command: g
At the clr.dll ModLoad, load SOS: .loadby sos clr
Run BPMD to break on the method for which you wish to see the disassembly. For example:
0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Adding pending breakpoints...
Continue again by running the 'Go' command: g
Run Name2EE to see the method descriptor. For example:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Module: 00a62edc
Assembly: TestArrayCompare.exe
Token: 06000001
MethodDesc: 00a637a4
Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[])
Not JITTED yet. Use !bpmd -md 00a637a4 to break on run.
Run the BPMD command in the "Not JITTED yet" line. For example:
0:000> !bpmd -md 00a637a4
MethodDesc = 00a637a4
Adding pending breakpoints...
Continue again: g
You should see "JITTED ..." in the Command window. Re-run the Name2EE command to see the address of the JIT code. For example:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Module: 00a62edc
Assembly: TestArrayCompare.exe
Token: 06000001
MethodDesc: 00a637a4
Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[])
JITTED Code Address: 00b500c8
Use the u command to disassemble, starting at the listed code address. For example:
0:000> u 00b500c8 L20
00b500c8 55 push ebp
00b500c9 8bec mov ebp,esp
00b500cb 57 push edi
00b500cc 56 push esi
...
(For the above, I was using WinDbg 6.3.9600.17200 X86 from the Windows 8.1 SDK.)
One handy reference is the SOS.dll (SOS Debugging Extension) reference page on MSDN.
You should use WinDbg with SOS/SOSEX, ensure that method you want to see x86 code for is JITted in method tables and then see actual unassembly with u command. Thus you would see actual code.
As others mentioned here, with ngen you could see code that is not exactly matches actual JIT compilation result. With Visual Studio it is also possible because JIT's compilation depends heavily on the fact if debugger is present or not.
UPD: Some clarification. WinDbg is a debugger also, but it is native one.
Here you can read about the technique in detail.
You could use Visual Studio Debugger by placing a breakpoint and then viewing the Dissassembly window (Alt+Ctrl+D) or try the Native Image Generator Tool (ngen.exe).
You can do a memory dump. However, note that the in-memory code does not necessarily contain every method.
ngen does AOT, or Ahead-of-time code generation, which can be different from JIT code.
Related
I'm relatively new to WinDbg, so I'm hoping this is just something obvious I'm missing. I have a .NET assembly that contains the function calls InitializeProcThreadAttributeList, UpdateProcThreadAttribute and DeleteProcThreadAttributeList, defined using P/Invoke. All three of those functions are imported from the "kernel32.dll" library. My goal is to trace these functions to understand the ntdll sys calls being used.
I tried to set a breakpoint with this command:
bp KERNEL32!InitializeProcThreadAttributeList
, but got this error:
Couldn't resolve error at 'KERNEL32!InitializeProcThreadAttributeList'
Next, I searched for any sign of this function using the following command:
x kernel32!*procthread*
I got this reply:
00007ffd`c7598588 KERNEL32!_imp_InitializeProcThreadAttributeList = <no type information>
I then tried to set a breakpoint on this stub? function like this:
bp kernel32!_imp_InitializeProcThreadAttributeList
Although it says the breakpoint has been defined, when I continue execution, it errors with this:
Unable to insert breakpoint 0 at 00007ffd`c7598588, Win32 error 0n998
"Invalid access to memory location."
I also tried setting the breakpoint with "bu", but that produced the same error.
Does anyone know how to set a breakpoint in this situation? Thank you in advance!
Most of the functions in kernel32 have been implemented in kernelbase.dll
and kernel32 only contains a thunk
the telltale sign is the IMP denoting imported from
_imp_InitializeProcThreadAttributeList
try setting bp kernelbase!InitializeProcThreadAttributeList
0:000> x /v kernel32!InitializeProcThreadAttributeList
pub func 761f4fc1 0 kernel32!InitializeProcThreadAttributeList (<no parameter info>)
0:000> u kernel32!InitializeProcThreadAttributeList l1
kernel32!InitializeProcThreadAttributeList:
761f4fc1 ff25c0181476 jmp dword ptr [kernel32!_imp__InitializeProcThreadAttributeList (761418c0)]
0:000> ? poi(kernel32!_imp__InitializeProcThreadAttributeList)
Evaluate expression: 1978493618 = 75ed6ab2
0:000> ln poi(kernel32!_imp__InitializeProcThreadAttributeList)
Exact matches:
KERNELBASE!InitializeProcThreadAttributeList (<no parameter info>)
0:000> bp poi(kernel32!_imp__InitializeProcThreadAttributeList)
0:000> bl
0 e 75ed6ab2 0001 (0001) 0:**** KERNELBASE!InitializeProcThreadAttributeList
I need to inspect code, that JIT emits for generic method with different struct parameters. I read articles about WinDbg and SOS.dll and it's possible to inspect non-generic methods. But for generic methods, which should be JIT-ed for each struct type there is no JIT-ed code in method table, where can i find it?
namespace ConsoleApp1
{
class Program
{
public void Foo<T>(T arg)
{
//some code here
}
static void Main(string[] args)
{
var program = new Program();
program.Foo("test");
program.Foo(1.0);
program.Foo(new Guid());
program.Foo((byte)1);
program.Foo((char)1);
program.Foo(1);
}
}
}
WinDbg:
0:006> .loadby sos clr
0:006> !Name2EE ConsoleApp1!ConsoleApp1.Program
Module: 00007ffa3abf4118
Assembly: ConsoleApp1.exe
Token: 0000000002000002
MethodTable: 00007ffa3abf5a18
EEClass: 00007ffa3abf24b8
Name: ConsoleApp1.Program
Dump method table
0:006> !DumpMT -md 00007ffa3abf5a18
EEClass: 00007ffa3abf24b8
Module: 00007ffa3abf4118
Name: ConsoleApp1.Program
mdToken: 0000000002000002
File: D:\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net462\ConsoleApp1.exe
BaseSize: 0x18
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
00007ffa9759c080 00007ffa970f7fb8 PreJIT System.Object.ToString()
00007ffa97604360 00007ffa970f7fc0 PreJIT System.Object.Equals(System.Object)
00007ffa97674770 00007ffa970f7fe8 PreJIT System.Object.GetHashCode()
00007ffa975cf570 00007ffa970f8000 PreJIT System.Object.Finalize()
00007ffa3ad005c0 00007ffa3abf5a10 JIT ConsoleApp1.Program..ctor()
00007ffa3ad00078 00007ffa3abf59e0 NONE ConsoleApp1.Program.Foo(!!0) // "base" IL code
00007ffa3ad00480 00007ffa3abf5a00 JIT ConsoleApp1.Program.Main(System.String[])
And ofc I got no code for Foo
0:006> !U 00007ffa3abf59e0
Not jitted yet
Is it any ideas?
I took your code and compiled it as x86 debug build. I then attached to the process and waited until it terminated.
I find the same result as you:
Entry MethodDe JIT Name
[...]
00250038 00204d34 NONE JitExample2.Program.Foo(!!0)
Here it says NONE, which has the meaning "not jitted".
0:000> !dumpmd 00204d34
Method Name: JitExample2.Program.Foo(!!0)
[...]
IsJitted: no
So the answer seems to be confirmed: it's not jitted.
I don't know any official method of getting a list of jitted generic methods. But with the help of !bpmd it's possible:
0:000> !bpmd JitExample2 JitExample2.Program.Foo
Found 1 methods in module 00204024...
MethodDesc = 00204d34
Setting breakpoint: bp 0025074A [JitExample2.Program.Foo[[System.Char, mscorlib]](Char)]
Setting breakpoint: bp 002506EA [JitExample2.Program.Foo[[System.Byte, mscorlib]](Byte)]
Setting breakpoint: bp 00250687 [JitExample2.Program.Foo[[System.Guid, mscorlib]](System.Guid)]
Setting breakpoint: bp 00250627 [JitExample2.Program.Foo[[System.Double, mscorlib]](Double)]
Setting breakpoint: bp 002505B0 [JitExample2.Program.Foo[[System.__Canon, mscorlib]](System.__Canon)]
Setting breakpoint: bp 002507AA [JitExample2.Program.Foo[[System.Int32, mscorlib]](Int32)]
You can then use the addresses after bp to show the JIT code:
0:000> !u 0025074A
Normal JIT generated code
JitExample2.Program.Foo[[System.Char, mscorlib]](Char)
Begin 00250728, size 4b
C:\Users\For example John\JitExample2\Program.cs # 8:
00250728 55 push ebp
00250729 8bec mov ebp,esp
0025072b 83ec10 sub esp,10h
0025072e 33c0 xor eax,eax
[...]
I'm debugging the source code for mscorlib1 with WinDbg/SOS. I'm curious, is it possible to get the managed function name if you see its address in assembly? For example, this is some of the code I'm seeing in the disassembly window:
00007ffd`7f035d7c 488d0d3d3af5ff lea rcx,[System_Private_CoreLib_ni+0x8797c0 (00007ffd`7ef897c0)]
00007ffd`7f035d83 e890728eff call System_Private_CoreLib_ni+0x20d018 (00007ffd`7e91d018)
00007ffd`7f035d88 488bf0 mov rsi,rax
00007ffd`7f035d8b b9874a0000 mov ecx,4A87h
00007ffd`7f035d90 e8834a91ff call System_Private_CoreLib_ni+0x23a818 (00007ffd`7e94a818)
00007ffd`7f035d95 488bc8 mov rcx,rax
00007ffd`7f035d98 e87356b9ff call System_Private_CoreLib_ni+0x4bb410 (00007ffd`7ebcb410)
00007ffd`7f035d9d 488bd0 mov rdx,rax
00007ffd`7f035da0 488bce mov rcx,rsi
00007ffd`7f035da3 e8e89fbdff call System_Private_CoreLib_ni+0x4ffd90 (00007ffd`7ec0fd90)
I want to find out what the names of some of these functions being call-ed are. I figure the command to use for this would be !dumpmd, but none of these commands seem to work:
!dumpmd 0x20d018
!dumpmd e890728eff
!dumpmd 00007ffd`7e91d018
All of them respond with "... is not a MethodDesc". How then can I get the managed function name from the assembly, or is it not possible?
1 mscorlib was recently renamed System.Private.CoreLib for .NET Core, so that's why you see that instead of mscorlib_ni.
!dumpmd 0x20d018
can't work, because you only pass the offset relative to the module. Without specifying the module (System_Private_CoreLib_ni), !dumpmd cannot know what you're referring to.
!dumpmt e890728eff
can't work, because you pass machine code to !dumpmt. e8 is the machine code for the assembly instruction call and the rest is a relative offset. To interpret that, !dumpmt would need to know the address of the instruction so that it can calculate the address of the method being called.
!dumpmt 00007ffd`7e91d018
could at least be plausible, because you pass an absolute address. That is a meaningful address. But it's not the address of a method table which !dumpmt expects.
With a given native address, you can use
!IP2MD <Code address> Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.
Actually the command will display much more, including the method name.
0:000> !ip2md 001fce80
MethodDesc: 00508ab4
Method Name: ReporterCmd.Program+<>c..cctor()
Class: 0025e10c
MethodTable: 00508ad0
mdToken: 06000027
Module: 00193fbc
IsJitted: yes
CodeAddr: 001fce48
Transparency: Critical
The sosex (download) command !mln as implemented by #Steve Johnson and mentioned in his answer is really helpful, since it will auto detect the nearest useful thing, so you needn't know in detail what you have.
0:000> !mln 001fce80
Method instance: (BEGIN=001fce48)(MD=00508ab4 disassemble)[ReporterCmd.Program+<>c..cctor()]
If you're learning about .NET internals, I recommend using !mln and then finding out how to get the same results using other methods so that you know about the relationship of things.
Pass the entire address to !sosex.mln
We have the following method in a class in one of our projects:
private unsafe void SomeMethod()
{
// Beginning of the method omitted for brevity
var nv = new Vector4[x];
fixed (Vector4* vp = nv)
{
fixed (float* tp = /* Source float ptr */)
{
fixed (double* ap = /* Source double ptr */)
{
for (var i = atlArray.Length - 1; i >= 0; --i)
{
vp[((i + 1) << 3) - 2] = new Vector4(tp[i], btt, 0.0f, 1.0f);
// Additional Vector4 construction omitted for brevity
nttp[i] = new Vector2(tp[i], this.ttvp);
nts[i] = string.Format(ap[i], /* etc. */);
}
}
}
}
this.ts = nts;
this.ttp = nttp;
this.V = nv; // <- This is a property setter
}
I've had to obfuscate this, but hopefully it's still clear enough to get an idea of what's going on.
On one of our developers' machines, in debug builds, the C# compiler removes the three assignments that occur after the fixed block is closed. If we attempt to put a breakpoint on these lines, the breakpoint skips to the ending brace of the method when the application starts. Code that appears between a fixed block and the end of a method is removed in other methods too, but puzzlingly, not in all of them.
After some experimentation, we found that turning on optimization for the affected project caused the missing code to be included. However, this work-around fails for our unit testing - the code is missing, and changing the optimization of the affected project and its test project does not help. We also found that moving the three assignments inside the inner-most fixed statement worked - it becomes clear why when examining the IL.
In the debug DLL built on the affected machine (with optimization turned off), a return op appears directly after ap is popped off the stack:
IL_03a1: nop
IL_03a2: ldc.i4.0
IL_03a3: conv.u
IL_03a4: stloc.s ap
IL_03a6: ret
This explains why moving the three assignments before the stloc instruction works. In the debug DLL built on my machine, the return op occurs in the expected place, after the three assignments:
IL_03a5: nop
IL_03a6: ldc.i4.0
IL_03a7: conv.u
IL_03a8: stloc.s ap
IL_03aa: nop
IL_03ab: ldc.i4.0
IL_03ac: conv.u
IL_03ad: stloc.s tp
IL_03af: nop
IL_03b0: ldc.i4.0
IL_03b1: conv.u
IL_03b2: stloc.s vp
IL_03b4: ldarg.0
IL_03b5: ldloc.s nts
IL_03b7: stfld string[] N.B.E.B::ts
IL_03bc: ldarg.0
IL_03bd: ldloc.s nttp
IL_03bf: stfld valuetype [SharpDX]SharpDX.Vector2[] N.B.E.B::ttp
IL_03c4: ldarg.0
IL_03c5: ldloc.s nv
IL_03c7: call instance void N.B.E.B::set_V(valuetype [SharpDX]SharpDX.Vector4[])
IL_03cc: nop
IL_03cd: ret
We've so far failed to produce an SSCCE - this seems to manifest only in very specific circumstances, and only in one of our projects. We've checked that the same versions of Visual Studio, the .NET framework, the C# compiler and MSBuild are being used on both machines. We've checked other potential differences like OS version and updates. Things appear to be the same on both machines (they are the same model of laptop). We're a bit puzzled, frankly. Any help would be much appreciated.
My colleague, the developer whose machine this was affecting, found a difference in the diagnostic output from the build - it was the C# compiler. We thought that MSBuild was using the csc.exe in the expected location (c:\Program Files (x86)\MSBuild\12.0\Bin), but bizarrely, it was actually executing a csc.exe in C:\Users\[user]\AppData\Local\Microsoft\VisualStudio\12.0\Extensions, which had a completely different version. We don't know how that compiler executable came to be there, or how it was being referenced by MSBuild, but once it was removed, MSBuild reverted to using the version of csc.exe in its home Bin directory, and the code is being built correctly now.
I had the following question regarding the searching of all dependencies of a dll during runtime.
I have general.dll which reads different files (other dlls, *.amd etc.) according to the used methods. I use this dll in my application, for example, Sample.exe (C#).
I am able to detect all dependencies (for Sample.exe) during runtime using Process Monitor (using filter by process name).
Please, prompt me how I can detect programmatically all dependencies which Sample.exe (with embedded general.dll) uses (reads) during runtime, i.e. what I need use in order to develop (in C#) similar functionality like in Process Monitor.
Thanks!
For C#/.NET directly:
You can use classes from System.Diagnostics, the property Process.Modules will fetch you a list of modules that have been loaded by the associated process, you can list all processes by calling Processes.GetProcesses().
For C++ side or if you want to invoke platform APIs:
You are looking for Win32 function EnumProcessModules(), which allows you to list all the modules (DLLs) loaded in a process referenced by a handle (which you can OpenProcess() by PID or whatever).
There is even a full example called Enumerating All Modules For a Process.
Detecting also other opened files:
I noticed late you wanted to detect also any other opened files, so I suggest the following hack: Hook Win32 API CreateFileW() (the Wide version is enough, Ascii one is just its wrapper) and log whatever is being opened (not only created, the function name can be misleading).
This is a working example code which shows what you'd need to do:
#include <windows.h>
#include <cstdio>
#include <cassert>
typedef HANDLE (WINAPI *CreateFileWType)(LPCWSTR, DWORD, DWORD,
LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
CreateFileWType origCreateFile;
HANDLE WINAPI myCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
// Log something about the file
printf("*** %S [%c%c]\n",
lpFileName,
(dwDesiredAccess & GENERIC_READ) ? 'R' : '-',
(dwDesiredAccess & GENERIC_WRITE) ? 'W' : '-');
// Call the original function
return origCreateFile(lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
}
int main()
{
// Get pointer to the function and verify it can be hot-patched
HMODULE hKernelBase = GetModuleHandle(TEXT("KernelBase"));
BYTE* addr = reinterpret_cast<BYTE*>(GetProcAddress(hKernelBase, "CreateFileW"));
assert(addr != NULL);
assert(addr[0] == 0x8B && addr[1] == 0xFF); // `mov edi, edi` prologue
// Save the original function location (after the prologue)
origCreateFile = reinterpret_cast<CreateFileWType>(addr + 2);
// Hot-patch the function to call our hook
DWORD dwOldProtect;
VirtualProtect(addr - 5, 7, PAGE_EXECUTE_READWRITE, &dwOldProtect);
addr[-5] = 0xE9; // jmp ...
*reinterpret_cast<DWORD*>(&addr[-4]) = reinterpret_cast<BYTE*>(&myCreateFileW) - addr;
*reinterpret_cast< WORD*>(&addr[ 0]) = 0xF9EB; // jmps $-5
VirtualProtect(addr - 5, 7, dwOldProtect, &dwOldProtect);
// Test that it all works - original application would continue here
fopen("input.txt", "r");
fopen("output.txt", "w");
return 0;
}
Example output:
*** input.txt [R-]
*** output.txt [-W]
This won't log any low-level system operations like loading DLLs, because such things are using NT call NtCreateFile() directly, but should work for most cases of file access fine. Also more error checking, converting into Managed C++/CLR or whatever is left as an exercise to the reader.
One of the possible approach could be that you dynamically inject a seperate dll (which can return back all the information) in process Sample.exe. For concept please refer
http://support.microsoft.com/kb/197571
Once the dll is loaded in Sample.exe you can extract all necessary information through your application
Edit: Please refer below link, it could be helpful
http://www.codeproject.com/Articles/38438/Monitoring-Process-Statistics-in-C-WPF