Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

!muf do mnie jeszcze, czyli sosex a dynamic assemblies

Biblioteka SOS, która dostarczana jest wraz z .NET Framework to nie jedyne źródło informacji o aplikacjach .NET analizowanych w WinDbg. Poza nią jest jeszcze Psscor4 (oraz wcześniejsza wersja - Psscor2, obie do ściągnięcia z Microsoft), która jest rozbudowaną wersją sos i jest najczęśniej zamiast niej używana. Kolejna to sosex, autorstwa Steve’a Johnsona, o której tu i ówdzie już wspominałem i właśnie o niej powiemy dziś parę słów.
Miesiąc temu pojawiła się najnowsza wersja tej biblioteki, w której pojawiło się sporo nowych poleceń, znacząco usprawniających debuggowanie aplikacji .NET. Dziś przedstawię jedno z nich, z pomocą którego możemy częściowo poradzić sobie z problemem, o którym pisałem kilka notek temu, a który dotyczył braku możliwości śledzenia kodu w ramach debuggowanej aplikacji. Nie musimy już szukać po necie ‘cudownej’ wersji WinDbg (o numerze 6.7.5.0), wystarczy najnowsza wersja sosex :)

Dynamic assemblies

Niechaj tłem do prezentacji nowych poleceń będzie krótki przykład z dynamic assembly.
Weźmy na ruszcik bibliotekę zawierającą klasę:

using System;
namespace pl.net.zine.Articles
{
  public class TestLib
  {
    public static void Test()
    {
      int i = 11;
      Console.WriteLine("Hello from TestLib! " + i.ToString());
      Console.ReadLine();
    }
  }
}

oraz prostą klasę testującą, ładującą dynamicznie naszą biblioteczkę:

using System;
using System.IO;
using System.Reflection;
namespace pl.net.zine.Articles
{
  class DynamicAssemblyDebugTester
  {
    public static void Main(string[] args)
    {
      Assembly ass = loadAssemblyWithPDB(
        "testlib.dll",
        "testlib.pdb");
      Console.WriteLine("Loaded!");
      Console.ReadLine();
      MethodInfo mi = ass.GetModule("TestLib.dll")
.GetType("pl.net.zine.Articles.TestLib")
.GetMethod("Test");
      mi.Invoke(null, null);
    }

    static Assembly loadAssemblyWithPDB(string dll, string pdb)
    {
      AppDomain domain = System.AppDomain.CurrentDomain;
      byte[] rawAssembly = loadFile(dll);
      byte[] rawSymbolStore = loadFile(pdb);
      Assembly assembly = domain.Load(rawAssembly, rawSymbolStore);
      return assembly;
    }

    static byte[] loadFile(string filename)
    {
      byte[] buffer = null;
      using (FileStream fs = new FileStream(filename, FileMode.Open))
      {
        buffer = new byte[(int)fs.Length];
        fs.Read(buffer, 0, buffer.Length);
      }
      return buffer;
    }
  }
}

Jak widać, do testów wykorzystuję wersję metody Assembly.Load (ściślej: AppDomain.Load, która korzysta z Assembly.Load) z dwoma parametrami - pierwszy odpowiada bibliotece, drugi - plikowi .pdb skojarzonemu z tą biblioteką:

domain.Load(rawAssembly, rawSymbolStore);

Jest również wersja z 1 parametrem - czyli samą biblioteką, bez skojarzonego z nią pdb.
Zobaczmy teraz, co ciekawego możemy zobaczyć w WinDbg podczas zabawy z dynamic assembly.
Uruchamiamy WinDbg, ładujemy program, puszczamy go do miejsca, w którym wyświetlone zostaje “Loaded!”, przerywamy działanie i ładujemy psscor4 oraz sosex, dociągamy symbole:

0:004> .load psscor4
0:004> .load sosex
0:004> .reload /f Articles.exe
*** WARNING: Unable to verify checksum for Articles.exe
0:004> lm m articles
start    end        module name
00d00000 00d0c000   Articles C (private pdb symbols)  C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\bin\Debug\Articles.pdb

po czym sprawdzamy nowe funkcjonalności sosex. Przełączamy się na właściwy wątek i zacznijmy od zrzucenia zarządzanego stosu oraz ustawienia się na odpowiedniej ramce stosu:

0:004> !threads
...
                                   PreEmptive   GC Alloc                Lock
       ID  OSID ThreadOBJ    State GC           Context       Domain   Count APT Exception
   0    1  19c4 006de220      a020 Enabled  022c103c:022c1fe8 006a64d0     1 MTA
   2    2  1c70 006ae508      b220 Enabled  00000000:00000000 006a64d0     0 MTA (Finalizer)

0:004> ~0s
eax=00000001 ebx=0034ec84 ecx=00000000 edx=00000000 esi=00000003 edi=022c0d1c
eip=751676f8 esp=0034eb1c ebp=0034eba4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
KERNEL32!ReadConsoleInternal+0x15:
751676f8 83c404          add     esp,4
0:000> !mk
Thread 0:
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\eb4e1e70734f6efb9c7de7ec5f452c9e\mscorlib.ni.dll
     ESP      EIP
00:U 0034eb1c 751676f8 KERNEL32!ReadConsoleInternal+0x15
01:U 0034eb24 75167361 KERNEL32!ReadConsoleA+0x40
02:U 0034ebac 750ef1c6 KERNEL32!ReadFileImplementation+0x75
03:M 0034ebf4 5ce91c8b DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)(+0x0 IL)(+0x0 Native)
04:M 0034ec74 5d4ff7e8 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Int32, Int32 ByRef)(+0x53 IL)(+0x8c Native)
05:M 0034ec9c 5d4ff6d0 System.IO.__ConsoleStream.Read(Byte[], Int32, Int32)(+0x5d IL)(+0x9c Native)
06:M 0034ecc4 5ce48bfb System.IO.StreamReader.ReadBuffer()(+0xa0 IL)(+0x3b Native)
07:M 0034ece0 5ce2560a System.IO.StreamReader.ReadLine()(+0x1b IL)(+0x16e Native)
08:M 0034ed00 5d505f45 System.IO.TextReader+SyncTextReader.ReadLine()(+0x0 IL)(+0x19 Native)
09:M 0034ed10 5d3fc292 System.Console.ReadLine()(+0x0 IL)(+0x12 Native)
0a:M 0034ed18 003700be pl.net.zine.Articles.DynamicAssemblyDebugTester.Main(System.String[])(+0x21 IL)(+0x4e Native) [C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\AssemblyLoad.cs @ 15,7]
0b:U 0034ed1c 5d9a21bb clr!CallDescrWorker+0x33
0c:U 0034ed3c 5d9a21bb clr!CallDescrWorker+0x33
0d:U 0034ed4c 5d9c4be2 clr!CallDescrWorkerWithHandler+0x8e
0e:U 0034edc8 5d9c4d84 clr!MethodDesc::CallDescr+0x194
0f:U 0034ef08 5d9c4db9 clr!MethodDesc::CallTargetWorker+0x21
10:U 0034ef24 5d9c4dd9 clr!MethodDescCallSite::Call_RetArgSlot+0x1c
11:U 0034ef3c 5dac7df5 clr!ClassLoader::RunMain+0x24c
12:U 0034f0a0 5dac7f00 clr!Assembly::ExecuteMainMethod+0xc1
13:U 0034f308 5dac7d17 clr!SystemDomain::ExecuteMainMethod+0x4ec
14:U 0034f7ec 5dac8109 clr!ExecuteEXE+0x58
15:U 0034f840 5dac800a clr!_CorExeMainInternal+0x19f
16:U 0034f88c 5db06870 clr!_CorExeMain+0x4e
17:U 0034f8c4 6e6b55ab mscoreei!_CorExeMain+0x38
18:U 0034f8d0 6e727f16 MSCOREE!ShellShim__CorExeMain+0x99
19:U 0034f8e0 6e724de3 MSCOREE!_CorExeMain_Exported+0x8
1a:U 0034f8e8 750c33ca KERNEL32!BaseThreadInitThunk+0xe
1b:U 0034f8f4 76ee9ed2 ntdll!__RtlUserThreadStart+0x70
1c:U 0034f934 76ee9ea5 ntdll!_RtlUserThreadStart+0x1b
0:000> !mframe 0a

Czas na fajerwerki!

0:000> !muf
pl.net.zine.Articles.DynamicAssemblyDebugTester.Main(string[]): void
    ass:System.Reflection.Assembly
    mi:System.Reflection.MethodInfo
        00370070 55              push    ebp
        00370071 8bec            mov     ebp,esp
        00370073 83ec1c          sub     esp,1Ch
        00370076 894dfc          mov     dword ptr [ebp-4],ecx
        00370079 833d3c31200000  cmp     dword ptr ds:[20313Ch],0
        00370080 7405            je      00370087
        00370082 e894638e5d      call    clr!JIT_DbgIsJustMyCode (5dc5641b)
        00370087 33d2            xor     edx,edx
        00370089 8955f4          mov     dword ptr [ebp-0Ch],edx
        0037008c 33d2            xor     edx,edx
        0037008e 8955f8          mov     dword ptr [ebp-8],edx
{
    IL_0000: nop
        00370091 90              nop
Assembly ass = loadAssemblyWithPDB(
        "testlib.dll",
        "testlib.pdb");
    IL_0001: ldstr "testlib.dll"
    IL_0006: ldstr "testlib.pdb"
    IL_000b: call pl.net.zine.Articles.DynamicAssemblyDebugTester::loadAssemblyWithPDB(string, string)
        00370092 8b0d30202b03    mov     ecx,dword ptr ds:[32B2030h]
        00370098 8b1534202b03    mov     edx,dword ptr ds:[32B2034h]
        0037009e ff15cc382000    call    dword ptr ds:[2038CCh]
        003700a4 8945f0          mov     dword ptr [ebp-10h],eax
    IL_0010: stloc.0  (ass)
        003700a7 8b45f0          mov     eax,dword ptr [ebp-10h]
        003700aa 8945f8          mov     dword ptr [ebp-8],eax
Console.WriteLine("Loaded!");
    IL_0011: ldstr "Loaded!"
    IL_0016: call System.Console::WriteLine
        003700ad 8b0d38202b03    mov     ecx,dword ptr ds:[32B2038h]
        003700b3 e8f46fab5c      call    mscorlib_ni+0x2570ac (5ce270ac)  [System.Console.WriteLine(System.String), MD=5cc58594]
    IL_001b: nop
        003700b8 90              nop
Console.ReadLine();
    IL_001c: call System.Console::ReadLine
        003700b9 e8c2c1085d      call    mscorlib_ni+0x82c280 (5d3fc280)  [System.Console.ReadLine(), MD=5cc584ec]
    IL_0021: pop
>>>>>>>>003700be 90              nop
MethodInfo mi = ass.GetModule("TestLib.dll").GetType("pl.net.zine.Articles.TestLib").GetMethod("Test");
    IL_0022: ldloc.0  (ass)
    IL_0023: ldstr "TestLib.dll"
    IL_0028: callvirt System.Reflection.Assembly::GetModule
        003700bf 8b153c202b03    mov     edx,dword ptr ds:[32B203Ch]
        003700c5 8b4df8          mov     ecx,dword ptr [ebp-8]
        003700c8 8b01            mov     eax,dword ptr [ecx]
        003700ca 8b403c          mov     eax,dword ptr [eax+3Ch]
        003700cd ff5004          call    dword ptr [eax+4]
        003700d0 8945ec          mov     dword ptr [ebp-14h],eax
    IL_002d: ldstr "pl.net.zine.Articles.TestLib"
    IL_0032: callvirt System.Reflection.Module::GetType
        003700d3 8b1540202b03    mov     edx,dword ptr ds:[32B2040h]
        003700d9 8b4dec          mov     ecx,dword ptr [ebp-14h]
        003700dc 8b01            mov     eax,dword ptr [ecx]
        003700de 8b4030          mov     eax,dword ptr [eax+30h]
        003700e1 ff5008          call    dword ptr [eax+8]
        003700e4 8945e8          mov     dword ptr [ebp-18h],eax
    IL_0037: ldstr "Test"
    IL_003c: callvirt System.Type::GetMethod
        003700e7 8b1544202b03    mov     edx,dword ptr ds:[32B2044h]
        003700ed 8b4de8          mov     ecx,dword ptr [ebp-18h]
        003700f0 3909            cmp     dword ptr [ecx],ecx
        003700f2 e83d33a95c      call    mscorlib_ni+0x233434 (5ce03434)  [System.Type.GetMethod(System.String), MD=5cc4e144]
        003700f7 8945e4          mov     dword ptr [ebp-1Ch],eax
    IL_0041: stloc.1  (mi)
        003700fa 8b45e4          mov     eax,dword ptr [ebp-1Ch]
        003700fd 8945f4          mov     dword ptr [ebp-0Ch],eax
mi.Invoke(null, null);
    IL_0042: ldloc.1  (mi)
    IL_0043: ldnull
    IL_0044: ldnull
    IL_0045: callvirt System.Reflection.MethodBase::Invoke
        00370100 6a00            push    0
        00370102 8b4df4          mov     ecx,dword ptr [ebp-0Ch]
        00370105 33d2            xor     edx,edx
        00370107 3909            cmp     dword ptr [ecx],ecx
        00370109 e86231b25c      call    mscorlib_ni+0x2c3270 (5ce93270)  [System.Reflection.MethodBase.Invoke(System.Object, System.Object[]), MD=5cc4d250]
    IL_004a: pop
        0037010e 90              nop
}
    IL_004b: ret
        0037010f 90              nop
        0037010f 90              nop

Zauważmy, że polecenie pokazało nam dokładnie miejsce, w którym jesteśmy (zaznaczyłem na czerwono, '>' to nie moja robota ;))
A tu jeszcze wersja skrócona:

0:000> !muf -s
pl.net.zine.Articles.DynamicAssemblyDebugTester.Main(string[]): void
    {
      Assembly ass = loadAssemblyWithPDB(
        "testlib.dll",
        "testlib.pdb");
      Console.WriteLine("Loaded!");
      Console.ReadLine();
      MethodInfo mi = ass.GetModule("TestLib.dll").GetType("pl.net.zine.Articles.TestLib").GetMethod("Test");
      mi.Invoke(null, null);
    }

Zaglądamy do helpa:

0:000> !sosex.help muf
SOSEX - Copyright 2007-2011 by Steve Johnson -
http://www.stevestechspot.com/
To report bugs or offer feedback about SOSEX, please email sjjohnson@pobox.com

muf
Usage !sosex.muf [MD Address | CodeAddress]  [-s] [-il] [-n]

Disassembles the method specified by the given MD or code address with interleaved source, IL and asm code.
If no MD or code address is specified, the current IP is used to determine the method to disassemble.

-s:      Display source code, if available
-il:     Display IL disassembly
-n:      Display native disassembly, if available
default: Display source, IL and native for method at current IP
[CIACH]

Puszczamy wykonanie i w momencie, kiedy pojawia się "Hello from TestLib! 11" przerywamy ponownie działanie i wskakujemy do debuggera.
Krótkie sprawdzenie listy załadowanych modułów:

0:000> lm
start    end        module name
00d00000 00d0c000   Articles C (private pdb symbols)  C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\bin\Debug\Articles.pdb
5cbd0000 5d993000   mscorlib_ni C (pdb symbols)          c:\websymbols\mscorlib.pdb\9B2E03D68C234C3DA8B047AD37E627DD1\mscorlib.pdb
5d9a0000 5e010000   clr        (pdb symbols)          c:\websymbols\clr.pdb\438C2C3CA1B74F2CB142EDCAFAC6B74E2\clr.pdb
5edd0000 5ee30000   clrjit     (deferred)            
60050000 6010e000   MSVCR100_CLR0400   (deferred)            
6e6b0000 6e716000   mscoreei   (pdb symbols)          c:\websymbols\mscoreei.pdb\C37CEAA96283461D863B6336B281284B2\mscoreei.pdb
6e720000 6e76a000   MSCOREE    (pdb symbols)          c:\websymbols\mscoree.pdb\5EB01A03276E4F6BB974E19A522150E12\mscoree.pdb
6f020000 6f030000   nlssorting   (deferred)            
74590000 7459c000   CRYPTBASE   (deferred)            
745a0000 74600000   SspiCli    (deferred)            
747a0000 7483d000   USP10      (deferred)            
74b30000 74bdc000   msvcrt     (deferred)            
74be0000 74ce0000   USER32     (deferred)            
74e10000 74eb0000   ADVAPI32   (deferred)            
74eb0000 74f40000   GDI32      (deferred)            
74f40000 74f59000   sechost    (deferred)            
74f60000 74fa6000   KERNELBASE   (deferred)            
74fb0000 7507c000   MSCTF      (deferred)            
750b0000 751c0000   KERNEL32   (pdb symbols)          c:\websymbols\wkernel32.pdb\820EEB5D68EF443ABBE61E837F814BE12\wkernel32.pdb
751c0000 7531c000   ole32      (deferred)            
760d0000 761c0000   RPCRT4     (deferred)            
761c0000 76220000   IMM32      (deferred)            
76330000 7633a000   LPK        (deferred)            
76340000 76397000   SHLWAPI    (deferred)            
76eb0000 77030000   ntdll      (pdb symbols)          c:\websymbols\wntdll.pdb\DCCFF2D483FA4DEE81DC04552C73BB5E2\wntdll.pdb
c:\websymbols\wkernel32.pdb\820EEB5D68EF443ABBE61E837F814BE12\wkernel32.pdb
751c0000 7531c000   ole32      (deferred)            
760d0000 761c0000   RPCRT4     (deferred)            
761c0000 76220000   IMM32      (deferred)            
76330000 7633a000   LPK        (deferred)            
76340000 76397000   SHLWAPI    (deferred)            
76eb0000 77030000   ntdll      (pdb symbols)          c:\websymbols\wntdll.pdb\DCCFF2D483FA4DEE81DC04552C73BB5E2\wntdll.pdb

Zaraz, momencik, a gdzie jest załadowany TestLib.dll? Na liście go nie widać... :( Powiem więcej - procexp również nic nie wie o dodatkowej bibliotece.
W tym momencie w sukurs przychodzi nam polecenie z psscor4:

0:008> !dda
Domain: Articles.exe
-------------------
Assembly: 0x006f9ff0 [TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null] Dynamic Module: 0x0020392c loaded at: 0x00390000 Size: 0x00001000(4,096)
--------------------------------------
Total 1 Dynamic Assemblies, Total size: 0x0(0) bytes.
=======================================

przy czym !dda to akronim !DumpDynamicAssemblies. Jak już jesteśmy przy tym poleceniu, to polecam uwadze przełącznik -save, do którego na pewno jeszcze kiedyś wrócimy.
Acha, czyli mamy go! :) Ok, spróbujmy teraz nowych poleceń z sosex:

0:000> !mk
Thread 0:
     ESP      EIP
00:U 0034e2d8 751676f8 KERNEL32!ReadConsoleInternal+0x15
01:U 0034e2e0 75167361 KERNEL32!ReadConsoleA+0x40
02:U 0034e368 750ef1c6 KERNEL32!ReadFileImplementation+0x75
03:M 0034e3b0 5ce91c8b DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)(+0x0 IL)(+0x0 Native)
04:M 0034e430 5d4ff7e8 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Int32, Int32 ByRef)(+0x53 IL)(+0x8c Native)
05:M 0034e458 5d4ff6d0 System.IO.__ConsoleStream.Read(Byte[], Int32, Int32)(+0x5d IL)(+0x9c Native)
06:M 0034e480 5ce48bfb System.IO.StreamReader.ReadBuffer()(+0xa0 IL)(+0x3b Native)
07:M 0034e49c 5ce2560a System.IO.StreamReader.ReadLine()(+0x1b IL)(+0x16e Native)
08:M 0034e4bc 5d505f45 System.IO.TextReader+SyncTextReader.ReadLine()(+0x0 IL)(+0x19 Native)
09:M 0034e4cc 5d3fc292 System.Console.ReadLine()(+0x0 IL)(+0x12 Native)
0a:M 0034e4d4 00370331
"estLib," was not found in the image list.
Debugger will attempt to load "estLib," at given base 00000000.
Please provide the full image name, including the extension (i.e. kernel32.dll)
for more reliable results.Base address and size overrides can be given as
.reload <image.ext>=<base>,<size>.
Unable to add module at 00000000
"estLib," was not found in the image list.
Debugger will attempt to load "estLib," at given base 00000000.
Please provide the full image name, including the extension (i.e. kernel32.dll)
for more reliable results.Base address and size overrides can be given as
.reload <image.ext>=<base>,<size>.
Unable to add module at 00000000
pl.net.zine.Articles.TestLib.Test()(+0x20 IL)(+0x51 Native)
0b:U 0034e4ec 5d9a21bb clr!CallDescrWorker+0x33
0c:U 0034e4fc 5d9c4be2 clr!CallDescrWorkerWithHandler+0x8e
0d:U 0034e578 5d9c4d84 clr!MethodDesc::CallDescr+0x194
0e:U 0034e6b8 5d9c4db9 clr!MethodDesc::CallTargetWorker+0x21
0f:U 0034e6d4 5d9c4dd9 clr!MethodDescCallSite::Call_RetArgSlot+0x1c
10:U 0034e6ec 5da34146 clr!CallWithValueTypes_RetArgSlotWrapper+0x5c
11:U 0034e8b0 5da34493 clr!InvokeImpl+0x621
12:U 0034eb7c 5da34655 clr!RuntimeMethodHandle::InvokeMethodFast+0x180
13:M 0034ec48 5ce8d689 System.RuntimeMethodHandle.InvokeMethodFast(System.IRuntimeMethodInfo, System.Object, System.Object[], System.Signature, System.Reflection.MethodAttributes, System.RuntimeType)(+0x16 IL)(+0x49 Native)
14:M 0034ec9c 5ce8d3d0 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, Boolean)(+0xfffffffd IL)(+0x150 Native)
15:M 0034ecd4 5ce8bfed System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)(+0x0 IL)(+0x1d Native)
16:M 0034ecfc 5ce93284 System.Reflection.MethodBase.Invoke(System.Object, System.Object[])(+0x0 IL)(+0x14 Native)
17:M 0034ed18 0037010e pl.net.zine.Articles.DynamicAssemblyDebugTester.Main(System.String[])(+0x4a IL)(+0x9e Native) [C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\AssemblyLoad.cs @ 17,7]
18:U 0034ed3c 5d9a21bb clr!CallDescrWorker+0x33
19:U 0034ed40 5d9ae001 clr!SigParser::GetElemType+0x28
1a:U 0034edf4 5d9c2a73 clr!MetaSig::MetaSig+0x3c
1b:U 0034ee0c 0034eeec 0x0034eeec
1c:U 0034ee80 5d9ae2ea clr!MethodDesc::GetSigFromMetadata+0x21
1d:U 0034ef08 5d9c4db9 clr!MethodDesc::CallTargetWorker+0x21
1e:U 0034ef24 5d9c4dd9 clr!MethodDescCallSite::Call_RetArgSlot+0x1c
1f:U 0034ef3c 5dac7df5 clr!ClassLoader::RunMain+0x24c
20:U 0034f0a0 5dac7f00 clr!Assembly::ExecuteMainMethod+0xc1
21:U 0034f308 5dac7d17 clr!SystemDomain::ExecuteMainMethod+0x4ec
22:U 0034f7ec 5dac8109 clr!ExecuteEXE+0x58
23:U 0034f840 5dac800a clr!_CorExeMainInternal+0x19f
24:U 0034f88c 5db06870 clr!_CorExeMain+0x4e
25:U 0034f8c4 6e6b55ab mscoreei!_CorExeMain+0x38
26:U 0034f8d0 6e727f16 MSCOREE!ShellShim__CorExeMain+0x99
27:U 0034f8e0 6e724de3 MSCOREE!_CorExeMain_Exported+0x8
28:U 0034f8e8 750c33ca KERNEL32!BaseThreadInitThunk+0xe
29:U 0034f8f4 76ee9ed2 ntdll!__RtlUserThreadStart+0x70
2a:U 0034f934 76ee9ea5 ntdll!_RtlUserThreadStart+0x1b

Niestety, sosex nie poradził sobie ze zrzutem ramki dynamicznego assembly - korzysta bowiem z listy modułów dostępnej przez lm, a tam naszego modułu nie ma :(. Pomóźmy mu zatem, i korzystając z informacji uzyskanych przed chwilą poleceniem !dda doładujmy .pdb:

0:000> .sympath+ C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\bin\Debug
Symbol search path is: srv*C:\websymbols*http://msdl.microsoft.com/downloads/symbols;c:\roboczy\2;C:\Roboczy\Programming\Projects\Dom\MiscTests\Articles\bin\Debug
Expanded Symbol search path is: srv*c:\websymbols*http://msdl.microsoft.com/downloads/symbols;c:\roboczy\2;c:\roboczy\programming\projects\dom\misctests\articles\bin\debug
0:000> .reload /f testlib.dll=0x00390000,0x00001000
0:000> lm m testlib
start    end        module name
00390000 00391000   testlib  M (private pdb symbols)  c:\roboczy\programming\projects\dom\misctests\articles\bin\debug\testlib.pdb

Sprawdzamy ponownie stos:

0:000> !mk
Thread 0:
     ESP      EIP
00:U 0034e2d8 751676f8 KERNEL32!ReadConsoleInternal+0x15
01:U 0034e2e0 75167361 KERNEL32!ReadConsoleA+0x40
02:U 0034e368 750ef1c6 KERNEL32!ReadFileImplementation+0x75
03:M 0034e3b0 5ce91c8b DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)(+0x0 IL)(+0x0 Native)
04:M 0034e430 5d4ff7e8 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Int32, Int32 ByRef)(+0x53 IL)(+0x8c Native)
05:M 0034e458 5d4ff6d0 System.IO.__ConsoleStream.Read(Byte[], Int32, Int32)(+0x5d IL)(+0x9c Native)
06:M 0034e480 5ce48bfb System.IO.StreamReader.ReadBuffer()(+0xa0 IL)(+0x3b Native)
07:M 0034e49c 5ce2560a System.IO.StreamReader.ReadLine()(+0x1b IL)(+0x16e Native)
08:M 0034e4bc 5d505f45 System.IO.TextReader+SyncTextReader.ReadLine()(+0x0 IL)(+0x19 Native)
09:M 0034e4cc 5d3fc292 System.Console.ReadLine()(+0x0 IL)(+0x12 Native)
0a:M 0034e4d4 00370331 pl.net.zine.Articles.TestLib.Test()(+0x20 IL)(+0x51 Native) [C:\Roboczy\Programming\Projects\Dom\MiscTests\TestLib\Loader.cs @ 11,7]
0b:U 0034e4ec 5d9a21bb clr!CallDescrWorker+0x33

i wszystko gra! :)
Czas na podgląd źródła oraz lokalnych zmiennych:

0:000> !mframe 0a
0:000> !muf
pl.net.zine.Articles.TestLib.Test(): void
    i:int
        003702e0 55              push    ebp
        003702e1 8bec            mov     ebp,esp
        003702e3 83ec10          sub     esp,10h
        003702e6 33c0            xor     eax,eax
        003702e8 8945fc          mov     dword ptr [ebp-4],eax
        003702eb 833dcc3b200000  cmp     dword ptr ds:[203BCCh],0
        003702f2 7405            je      003702f9
        003702f4 e822618e5d      call    clr!JIT_DbgIsJustMyCode (5dc5641b)
{
    IL_0000: nop
        003702f9 90              nop
int i = 11;
    IL_0001: ldc.i4.s 11(0xb)
    IL_0003: stloc.0  (i)
        003702fa c745fc0b000000  mov     dword ptr [ebp-4],0Bh
Console.WriteLine("Hello from TestLib! " + i.ToString());
    IL_0004: ldstr "Hello from TestLib! "
    IL_0009: ldloca.s 0 (i)
    IL_000b: call System.Int32::ToString
        00370301 8b0548202b03    mov     eax,dword ptr ds:[32B2048h]
        00370307 8945f8          mov     dword ptr [ebp-8],eax
        0037030a 8d4dfc          lea     ecx,[ebp-4]
        0037030d e84ef3a85c      call    mscorlib_ni+0x22f660 (5cdff660)  [System.Int32.ToString(), MD=5cc51e30]
        00370312 8945f4          mov     dword ptr [ebp-0Ch],eax
    IL_0010: call System.String::Concat
        00370315 8b55f4          mov     edx,dword ptr [ebp-0Ch]
        00370318 8b4df8          mov     ecx,dword ptr [ebp-8]
        0037031b e88074b15c      call    mscorlib_ni+0x2b77a0 (5ce877a0)  [System.String.Concat(System.String, System.String), MD=5cc4bdcc]
        00370320 8945f0          mov     dword ptr [ebp-10h],eax
    IL_0015: call System.Console::WriteLine
        00370323 8b4df0          mov     ecx,dword ptr [ebp-10h]
        00370326 e8816dab5c      call    mscorlib_ni+0x2570ac (5ce270ac)  [System.Console.WriteLine(System.String), MD=5cc58594]
    IL_001a: nop
        0037032b 90              nop
Console.ReadLine();
    IL_001b: call System.Console::ReadLine
        0037032c e84fbf085d      call    mscorlib_ni+0x82c280 (5d3fc280)  [System.Console.ReadLine(), MD=5cc584ec]
    IL_0020: pop
>>>>>>>>00370331 90              nop
}
    IL_0021: ret
        00370332 90              nop
        00370332 90              nop
0:000> !muf -s
pl.net.zine.Articles.TestLib.Test(): void
    {
      int i = 11;
      Console.WriteLine("Hello from TestLib! " + i.ToString());
      Console.ReadLine();
    }
0:000> !mdv
Frame 0xa: (pl.net.zine.Articles.TestLib.Test()):
[L0]:i:0x0000000b (System.Int32)

i to chyba tyle, jeśli idzie o debuggowanie dynamic assemblies z użyciem najnowszej wersji sosex :)

I na koniec

Zgłosiłem już Steve’owi Johnsonowi problem z dynamic assemblies oraz braku wsparcia dla dynamicznie ładowanych pdb, a także inny - związany z obsługą Source Servera przy pobieraniu źródeł - jak wiemy WinDbg w wersjach innych, niż 6.7.5.0 tego nie wspiera, ale miałem nadzieję, że sosex wchodząc z poleceniami typu !mu, !mt oraz !muf nie będzie się na tym opierał i samodzielnie to obsłuży... no cóż, uzbrajam się w cierpliwość i być może w kolejnych wersjach wspomniane problemy zostaną rozwiązane.
Z drugiej strony - Visual Studio ma bardzo dobre wsparcie dla dynamic assemblies - pojawiają się na liście załadowanych modułów, VS korzysta z załadowanego do pamięci pliku z symbolami i jedyne o co prosi, to lokalizacja plików źródłowych, po czym daje pełne możliwości debuggera, które znamy i kochamy :). Trzeba oczywiście pamiętać, że w VS mamy do czynienia z dedykowanym debuggerem zarządzanym, natomiast WinDbg jest debuggerem natywnym z zestawem dodatkowych poleceń. Nie zawsze mamy jednak możliwość skorzystania z Visual Studio i wówczas opisana wyżej technika może być bardzo pomocna.

Ale o tym w następnym odcinku :)

Opublikowane 12 października 2011 23:41 przez mgrzeg

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

października 13, 2011 07:22

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems