Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rmi1974/dc308b1958c17e067afa58e4f5684759 to your computer and use it in GitHub Desktop.
Save rmi1974/dc308b1958c17e067afa58e4f5684759 to your computer and use it in GitHub Desktop.
Debugging of managed code using WinDBG/CorDbg in Wine #wine #debug #dotnet #commandlinefu

Debugging of managed code using WinDBG/CorDbg in Wine

Courtesy of Wine Bugzilla #46842.

Prerequisites

  • Microsoft .NET Framework 4.x installed in WINEPREFIX (use 'winetricks' to install it)
  • Microsoft Debugging Tools for Windows installed in WINEPREFIX. Get them here (64-bit) and here (32-bit).

Set native overrides:

export WINEDLLOVERRIDES="dbghelp,dbgeng=n"

Set debug channels to get diagnostics about loading of dlls intermixed with debugger output:

export WINEDEBUG="+loaddll,+process"

Setup symbol server:

export _NT_SYMBOL_PATH="SRV*z:\home\focht\Downloads\debug_symbols*http://msdl.microsoft.com/download/symbols"

Debug the managed application

$ wine "c:\\Program Files\\Debugging Tools for Windows (x86)\\cdb.exe" ./bug46842.exe

0:000> sxe ld clrjit

0:000> g

0:000> .loadby sos clr

0:000> !name2ee *!System.Double.TryParse

Module:      79881000
Assembly:    mscorlib.dll
Token:       06000b97
MethodDesc:  798f5440
Name:        System.Double.TryParse(System.String, Double ByRef)
JITTED Code Address: 79b22cb0
-----------------------
Token:       06000b98
MethodDesc:  798f544c
Name:        System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.IFormatProvider, Double ByRef)
JITTED Code Address: 79ac767c
-----------------------
Token:       06000bab
MethodDesc:  798f55ac
Name:        System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
JITTED Code Address: 79ac76b4
--------------------------------------
Module:      00372e9c
Assembly:    bug46842.exe

0:000> bp 79b22cb0

0:000> g
...

0:000> g
Unable to parse '123AE6'.
Breakpoint 0 hit

0:000> g
Unable to parse ''.
Breakpoint 0 hit

0:000> !CLRStack -a
OS Thread Id: 0x30 (0)
Child SP IP       Call Site
0032f2cc 79b22cb0 System.Double.TryParse(System.String, Double ByRef)
    PARAMETERS:
        s (<CLR reg>) = 0x00c91228
        result (<CLR reg>) = 0x0032f2fc

0032f2d0 003b0182 Example.Main()
    LOCALS:
        0x0032f2ec = 0x00c9b1e8
        0x0032f2fc = 0x00000000
        0x0032f2e8 = 0x00c91228
        0x0032f2e4 = 0x00c9b1e8
        0x0032f2e0 = 0x00c9b1e8
        0x0032f2f8 = 0x00000006
        0x0032f2f4 = 0x00000001

0032f538 791421db [GCFrame: 0032f538] 

0:000> !IP2MD @eip
MethodDesc:   798f5440
Method Name:  System.Double.TryParse(System.String, Double ByRef)
Class:        798d5424
MethodTable:  79b9a380
mdToken:      06000b97
Module:       79881000
IsJitted:     yes
CodeAddr:     79b22cb0
Transparency: Safe critical

0:000> !DumpIL 798f5440
ilAddr = 79bcfe1b
IL_0000: ldarg.0 
IL_0001: ldc.i4 231
IL_0006: call System.Globalization.NumberFormatInfo::get_CurrentInfo
IL_000b: ldarg.1 
IL_000c: call System.Double::TryParse
IL_0011: ret 

0:000> l+t

...
0:000> t
...

0:000> !IP2MD @eip
MethodDesc:   798f55ac
Method Name:  System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
Class:        798d5424
MethodTable:  79b9a380
mdToken:      06000bab
Module:       79881000
IsJitted:     yes
CodeAddr:     79ac76b4
Transparency: Transparent

0:000> !DumpIL 798f55ac
ilAddr = 79c1b030
IL_0000: ldarg.0 
IL_0001: brtrue.s IL_0010
IL_0003: ldarg.3 
IL_0004: ldc.r8 0.000000
IL_000d: stind.r8 
IL_000e: ldc.i4.0 
IL_000f: ret 
IL_0010: ldarg.0 
IL_0011: ldarg.1 
IL_0012: ldarg.2 
IL_0013: ldarg.3 
IL_0014: call System.Number::TryParseDouble
IL_0019: stloc.0 
IL_001a: ldloc.0 
IL_001b: brtrue.s IL_0077
IL_001d: ldarg.0 
IL_001e: callvirt System.String::Trim
IL_0023: stloc.1 
IL_0024: ldloc.1 
IL_0025: ldarg.2 
IL_0026: callvirt System.Globalization.NumberFormatInfo::get_PositiveInfinitySymbol
IL_002b: callvirt System.String::Equals
IL_0030: brfalse.s IL_003f
IL_0032: ldarg.3 
IL_0033: ldc.r8 1.#INF00
IL_003c: stind.r8 
IL_003d: br.s IL_0077
IL_003f: ldloc.1 
IL_0040: ldarg.2 
IL_0041: callvirt System.Globalization.NumberFormatInfo::get_NegativeInfinitySymbol
IL_0046: callvirt System.String::Equals
IL_004b: brfalse.s IL_005a
IL_004d: ldarg.3 
IL_004e: ldc.r8 -1.#INF00
IL_0057: stind.r8 
IL_0058: br.s IL_0077
IL_005a: ldloc.1 
IL_005b: ldarg.2 
IL_005c: callvirt System.Globalization.NumberFormatInfo::get_NaNSymbol
IL_0061: callvirt System.String::Equals
IL_0066: brfalse.s IL_0075
IL_0068: ldarg.3 
IL_0069: ldc.r8 -1.#IND00
IL_0072: stind.r8 
IL_0073: br.s IL_0077
IL_0075: ldc.i4.0 
IL_0076: ret 
IL_0077: ldc.i4.1 
IL_0078: ret 

...
0:000> t
...
0:000> !IP2MD @eip
MethodDesc:   799b7104
Method Name:  System.Number.TryParseDouble(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
Class:        798dc1e4
MethodTable:  79ba6a48
mdToken:      06000e0c
Module:       79881000
IsJitted:     yes
CodeAddr:     79b11e98
Transparency: Safe critical

0:000> !DumpIL 799b7104
ilAddr = 79c1f76c
IL_0000: ldc.i4.s 114
IL_0002: conv.u 
IL_0003: localloc 
IL_0005: stloc.0 
IL_0006: ldloca.s VAR OR ARG 1
IL_0008: ldloc.0 
IL_0009: newobj NumberBuffer::.ctor
IL_000e: stobj NumberBuffer
IL_0013: ldarg.3 
IL_0014: ldc.r8 0.000000
IL_001d: stind.r8 
IL_001e: ldarg.0 
IL_001f: ldarg.1 
IL_0020: ldloca.s VAR OR ARG 1
IL_0022: ldarg.2 
IL_0023: ldc.i4.0 
IL_0024: call System.Number::TryStringToNumber
IL_0029: brtrue.s IL_002d
IL_002b: ldc.i4.0 
IL_002c: ret 
IL_002d: ldloca.s VAR OR ARG 1
IL_002f: call NumberBuffer::PackForNative
IL_0034: ldarg.3 
IL_0035: call System.Number::NumberBufferToDouble
IL_003a: brtrue.s IL_003e
IL_003c: ldc.i4.0 
IL_003d: ret 
IL_003e: ldc.i4.1 
IL_003f: ret

...

0:000> !IP2MD @eip
MethodDesc:   799b7140
Method Name:  System.Number.TryStringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
Class:        798dc1e4
MethodTable:  79ba6a48
mdToken:      06000e13
Module:       79881000
IsJitted:     yes
CodeAddr:     79ac6350
Transparency: Safe critical

0:000> !DumpIL 799b7140
ilAddr = 79c1f974
IL_0000: ldarg.0 
IL_0001: brtrue.s IL_0005
IL_0003: ldc.i4.0 
IL_0004: ret 
IL_0005: ldarg.0 
IL_0006: stloc.3 
IL_0007: ldloc.3 
IL_0008: conv.i 
IL_0009: dup 
IL_000a: brfalse.s IL_0012
IL_000c: call System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData
IL_0011: add 
IL_0012: stloc.0 
IL_0013: ldloc.0 
IL_0014: stloc.1 
IL_0015: ldloca.s VAR OR ARG 1
IL_0017: ldarg.1 
IL_0018: ldarg.2 
IL_0019: ldarg.3 
IL_001a: ldarg.s VAR OR ARG 4
IL_001c: ldarg.s VAR OR ARG 5
IL_001e: call System.Number::ParseNumber
IL_0023: brfalse.s IL_0043
IL_0025: ldloc.1 
IL_0026: ldloc.0 
IL_0027: sub 
IL_0028: ldc.i4.2 
IL_0029: div 
IL_002a: conv.i8 
IL_002b: ldarg.0 
IL_002c: callvirt System.String::get_Length
IL_0031: conv.i8 
IL_0032: bge.s IL_0047
IL_0034: ldarg.0 
IL_0035: ldloc.1 
IL_0036: ldloc.0 
IL_0037: sub 
IL_0038: ldc.i4.2 
IL_0039: div 
IL_003a: conv.i8 
IL_003b: conv.i4 
IL_003c: call System.Number::TrailingZeros
IL_0041: brtrue.s IL_0047
IL_0043: ldc.i4.0 
IL_0044: stloc.2 
IL_0045: leave.s IL_004b
IL_0047: ldnull 
IL_0048: stloc.3 
IL_0049: ldc.i4.1 
IL_004a: ret 
IL_004b: ldloc.2 
IL_004c: ret 

0:000> !clrstack -a
OS Thread Id: 0x30 (0)
Child SP IP       Call Site
0032f1cc 79ac6350 System.Number.TryStringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
    PARAMETERS:
        str (<CLR reg>) = 0x00c91228
        options (<CLR reg>) = 0x000000e7
        number (0x0032f1dc) = 0x0032f270
        sb (0x0032f1d8) = 0x00000000
        numfmt (0x0032f1d4) = 0x00c9b584
        parseDecimal (0x0032f1d0) = 0x00000000
    LOCALS:
        <no data>
        <no data>
        <no data>
        <no data>

0032f1e0 79b11f12 System.Number.TryParseDouble(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
    PARAMETERS:
        value = <no data>
        options = <no data>
        numfmt = <no data>
        result (<CLR reg>) = 0x0032f2fc
    LOCALS:
        <no data>
        <no data>

0032f2a4 79ac76d3 System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
    PARAMETERS:
        s (<CLR reg>) = 0x00c91228
        style = <no data>
        info (<CLR reg>) = 0x00c9b584
        result (<CLR reg>) = 0x0032f2fc
    LOCALS:
        <no data>
        <no data>

0032f2c0 79b22ccc System.Double.TryParse(System.String, Double ByRef)
    PARAMETERS:
        s = <no data>
        result = <no data>

0032f2d0 003b0182 Example.Main()
    LOCALS:
        0x0032f2ec = 0x00c9b1e8
        0x0032f2fc = 0x00000000
        0x0032f2e8 = 0x00c91228
        0x0032f2e4 = 0x00c9b1e8
        0x0032f2e0 = 0x00c9b1e8
        0x0032f2f8 = 0x00000006
        0x0032f2f4 = 0x00000001

0032f538 791421db [GCFrame: 0032f538] 

0:000> !do 0x00c91228
Name:        System.String
MethodTable: 79b9f9ac
EEClass:     798d8bb0
Size:        14(0xe) bytes
File:        C:\windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
79ba2978  40000ed        4         System.Int32  1 instance        0 m_stringLength
79ba1dc8  40000ee        8          System.Char  1 instance        0 m_firstChar
79b9f9ac  40000ef        8        System.String  0   shared   static Empty
    >> Domain:Value  001430c0:00c91228 <<

0:000> !IP2MD @eip
MethodDesc:   799b71d8
Method Name:  System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
Class:        798dc1e4
MethodTable:  79ba6a48
mdToken:      06000e20
Module:       79881000
IsJitted:     yes
CodeAddr:     79ac5db0
Transparency: Critical

0:000> !clrstack
OS Thread Id: 0x30 (0)
Child SP IP       Call Site
0032f1a0 79ac5db0 System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
0032f1b4 79ac6394 System.Number.TryStringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
0032f1e0 79b11f12 System.Number.TryParseDouble(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
0032f2a4 79ac76d3 System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef)
0032f2c0 79b22ccc System.Double.TryParse(System.String, Double ByRef)
0032f2d0 003b0182 Example.Main()
0032f538 791421db [GCFrame: 0032f538] 

0:000> !DumpIL 799b71d8
ilAddr = 79c1fd28
IL_0000: ldarg.2 
IL_0001: ldc.i4.0 
IL_0002: stfld NumberBuffer::scale
IL_0007: ldarg.2 
IL_0008: ldc.i4.0 
IL_0009: stfld NumberBuffer::sign
IL_000e: ldnull 
IL_000f: stloc.2 
IL_0010: ldnull 
IL_0011: stloc.3 
IL_0012: ldnull 
IL_0013: stloc.s VAR OR ARG 4
IL_0015: ldnull 
IL_0016: stloc.s VAR OR ARG 5
IL_0018: ldc.i4.0 
IL_0019: stloc.s VAR OR ARG 6
IL_001b: ldarg.1 
IL_001c: ldc.i4 256
IL_0021: and 
IL_0022: brfalse.s IL_0064
IL_0024: ldarg.s VAR OR ARG 4
IL_0026: callvirt System.Globalization.NumberFormatInfo::get_CurrencySymbol
IL_002b: stloc.2 
IL_002c: ldarg.s VAR OR ARG 4
IL_002e: ldfld System.Globalization.NumberFormatInfo::ansiCurrencySymbol
IL_0033: brfalse.s IL_003d
IL_0035: ldarg.s VAR OR ARG 4
IL_0037: ldfld System.Globalization.NumberFormatInfo::ansiCurrencySymbol
IL_003c: stloc.3 
IL_003d: ldarg.s VAR OR ARG 4
IL_003f: callvirt System.Globalization.NumberFormatInfo::get_NumberDecimalSeparator
IL_0044: stloc.s VAR OR ARG 4
IL_0046: ldarg.s VAR OR ARG 4
IL_0048: callvirt System.Globalization.NumberFormatInfo::get_NumberGroupSeparator
IL_004d: stloc.s VAR OR ARG 5
IL_004f: ldarg.s VAR OR ARG 4
IL_0051: callvirt System.Globalization.NumberFormatInfo::get_CurrencyDecimalSeparator
IL_0056: stloc.0 
IL_0057: ldarg.s VAR OR ARG 4
IL_0059: callvirt System.Globalization.NumberFormatInfo::get_CurrencyGroupSeparator
IL_005e: stloc.1 
IL_005f: ldc.i4.1 
IL_0060: stloc.s VAR OR ARG 6
IL_0062: br.s IL_0074
IL_0064: ldarg.s VAR OR ARG 4
IL_0066: callvirt System.Globalization.NumberFormatInfo::get_NumberDecimalSeparator
IL_006b: stloc.0 
IL_006c: ldarg.s VAR OR ARG 4
IL_006e: callvirt System.Globalization.NumberFormatInfo::get_NumberGroupSeparator
IL_0073: stloc.1 
IL_0074: ldc.i4.0 
IL_0075: stloc.s VAR OR ARG 7
IL_0077: ldc.i4.0 
IL_0078: stloc.s VAR OR ARG 8

...

0:000> !clrstack -a
OS Thread Id: 0x30 (0)
Child SP IP       Call Site
0032f150 79ac6260 System.Number.MatchChars(Char*, System.String)
    PARAMETERS:
        p (<CLR reg>) = 0x00c91230
        str (<CLR reg>) = 0x00c91748
    LOCALS:
        <no data>
        <no data>
        <no data>

0032f154 79ac5e7d System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean)
    PARAMETERS:
        str (0x0032f16c) = 0x0032f1b8
        options (0x0032f18c) = 0x000000e7
        number (0x0032f1b0) = 0x0032f270
        sb (0x0032f1ac) = 0x00000000
        numfmt (0x0032f1a8) = 0x00c9b584
        parseDecimal (0x0032f1a4) = 0x00000000
    LOCALS:
        0x0032f168 = 0x00c9b6a0
        0x0032f164 = 0x00c9b6b0
        0x0032f160 = 0x00000000
        0x0032f15c = 0x00000000
        0x0032f158 = 0x00000000
        0x0032f154 = 0x00000000
        0x0032f188 = 0x00000000
        <CLR reg> = 0x00000000
        <CLR reg> = 0x00000001
        0x0032f184 = 0x00000000
        0x0032f180 = 0x00000000
        <no data>
        0x0032f17c = 0x00c91230
        <CLR reg> = 0x00000000
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>

...

0:000> !do 0x00c91748
Name:        System.String
MethodTable: 79b9f9ac
EEClass:     798d8bb0
Size:        16(0x10) bytes
File:        C:\windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      +
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
79ba2978  40000ed        4         System.Int32  1 instance        1 m_stringLength
79ba1dc8  40000ee        8          System.Char  1 instance       2b m_firstChar
79b9f9ac  40000ef        8        System.String  0   shared   static Empty
    >> Domain:Value  001430c0:00c91228 <<

Links

@john-peterson
Copy link

wine c:\\windbg\\cdb.exe notepad.exe
Unable to set engine callbacks, HRESULT 0x80004001

Any ideas?

@danielkrajnik
Copy link

Doesn't work: Unable to find module 'clr'

@rmi1974
Copy link
Author

rmi1974 commented Nov 3, 2023

wine c:\\windbg\\cdb.exe notepad.exe
Unable to set engine callbacks, HRESULT 0x80004001

Any ideas?

Unable to set engine callbacks, HRESULT 0x80004001

Since you left out other messages, I can only guess it was something like this:

fixme:dbgeng:debugclient_SetOutputCallbacks 00971BB0, 01052B58 stub. Unable to set engine callbacks, HRESULT 0x80004001 fixme:dbgeng:debugclient_EndSession 00971BB0, 0 stub.

Which basically means you missed some of the information I provided. I wrote:

Set native overrides:

export WINEDLLOVERRIDES="dbghelp,dbgeng=n"

If you closed the shell then this dll override setting will obviously be lost. You have to persist it in registry (also using 'winecfg' to set overrides).
Again: You have to override dbgeng and dbghelp modules to native = force the use of dll provided by Debugging Tools for Windows all the time. Wine's builtin debug modules WILL NOT WORK here.

@rmi1974
Copy link
Author

rmi1974 commented Nov 3, 2023

Doesn't work: Unable to find module 'clr'

Since you didn't provide much information, leaving out some preceding Wine messages/errors I can only guess what might be the problem. Most likely there were messages like this in console when the debugger tried to load the .NET binary:

err:module:fixup_imports_ilonly mscoree.dll not found, IL-only binary L"numberformatinfo.exe" cannot be loaded err:module:loader_init Importing dlls for L"C:\\Program Files\\Debugging Tools for Windows (x86)\\numberformatinfo.exe" failed, status c0000135

Any commands related to managed debugger will not work in this case.

Make sure you really have native MS .NET Framework properly installed in the WINEPREFIX. Preferably using 'winetricks' which also removes Wine-Mono ('winetricks -q dotnet40' etc.).
Again: Managed debugging will not work with Wine-Mono by design.

Since all the referenced tickets and links are about MS .NET I didn't mention it in "prerequisites" because I thought this is common knowledge. I added that information under "prerequisites" to make sure it's known to everyone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment