Using SoS to debug 32-bit code in a 64-bit dump with WinDbg

Update: I have since turned this into a WinDbg extension.

Let us say that you for some reason have made a 64-bit dump of a 32-bit .NET process (possibly by mistake), and you need to investigate it. It used to be that you could just load it into the 32-bit version of WinDbg and use !wow64ext.sw to switch into the 32-bit view of the process, and then SOS would work fine. However if you try this with .NET 4.5/4.5.1 then this is the result:
SOS does not support the current target architecture.

So… what can one do then? Attempting to remove some checks from windbg and sos perhaps?

It turns out that this is possible. The following instructions works with windbg from debugging tools for Windows 8.1 and Windows 10.

First open the dump in a windbg instance, shift it to the 32-bit view with !wow64ext.sw, load sos and then attempt to run some sos command. You will get the error message above.

Then start another windbg and attach that to the first instance. First we need to make SoS use the effective architecture instead of the executing architecture. The address we need to patch has changed a bit between versions of sos.dll (probably due to compiler optimizations), so do an assembly listing of sos!ArchQuery with the uf command:

0:005> uf sos!ArchQuery
sos!ArchQuery:
0473c5b0 55 push ebp
0473c5b1 8bec mov ebp,esp
0473c5b3 51 push ecx
0473c5b4 a1907f7a04 mov eax,dword ptr [sos!g_ExtControl (047a7f90)]
0473c5b9 56 push esi
0473c5ba 8b08 mov ecx,dword ptr [eax]
0473c5bc 8d55fc lea edx,[ebp-4]
0473c5bf 52 push edx
0473c5c0 50 push eax
0473c5c1 33f6 xor esi,esi
; IDebugControl5[36] 90 -> BC: IDebugControl::GetEffectiveProcessorType
; 0x0473c5c3+2 - 0x0473c5b0 = 0x15. sos!ArchQuery+0x15
0473c5c3 ff9190000000 call dword ptr [ecx+90h] ; IDebugControl::GetExecutingProcessorType dbgeng!DebugCreate+0x3c5f
0473c5c9 8b45fc mov eax,dword ptr [ebp-4]
0473c5cc 3d4c010000 cmp eax,14Ch
0473c5d1 750a jne sos!ArchQuery+0x2d (0473c5dd) Branch

Look for the bolded line. Then calculate the address of that plus 2 and subtract the first address listed, like I have done in the blue comment. Now you have the relative address from the start of sos!ArchQuery to patch (e.g. 0x15 in my case). Now you can in the future refere to that location in your sos.dll version as sos!ArchQuery + <addr>. We have to patch that from 0x90 (IDebugControl::GetExecutingProcessorType) to 0xBC (IDebugControl::GetEffectiveProcessorType):

eb sos!ArchQuery+0x15 0xBC

(replace 0x15 with the relative address you just calculated).

Now this makes some of the sos commands works, e.g. !threads and !dumpstack works now, but others such as !CLRStack does not. This can be fixed by patching the function dbgeng!X86MachineInfo::ConvertCanonContextToTarget. Make a listing of this:

dbgeng!X86MachineInfo::ConvertCanonContextToTarget:
693ceef8 8bff            mov     edi,edi
693ceefa 55              push    ebp
693ceefb 8bec            mov     ebp,esp
693ceefd 53              push    ebx
693ceefe 56              push    esi
693ceeff 57              push    edi
693cef00 8b7d0c          mov     edi,dword ptr [ebp+0Ch]
693cef03 33db            xor     ebx,ebx
693cef05 57              push    edi
693cef06 53              push    ebx
693cef07 ff7510          push    dword ptr [ebp+10h]
693cef0a 8bf1            mov     esi,ecx
693cef0c e8c5690d00      call    dbgeng!memset (694a58d6)
693cef11 8b4608          mov     eax,dword ptr [esi+8]
693cef14 83c40c          add     esp,0Ch
693cef17 81b8a800000001100000 cmp dword ptr [eax+0A8h],1001h
693cef21 7715            ja      dbgeng!X86MachineInfo::ConvertCanonContextToTarget+0x40 (693cef38)

dbgeng!X86MachineInfo::ConvertCanonContextToTarget+0x2b:
693cef23 81ffcc000000    cmp     edi,0CCh
693cef29 7264            jb      dbgeng!X86MachineInfo::ConvertCanonContextToTarget+0x97 (693cef8f)

We need to patch this check out (note that your windbg instance might have problems with non-x86 dumps after this). So just replace the conditional jump with two nops:

ew dbgeng!X86MachineInfo::ConvertCanonContextToTarget+0x29 0x9090

Again the 0x29 may be different in your version, it is the bolded address minus the start address. Also the value compared to is 0x1004 instead of 0x1001 in debugging tools for windows 10 (probably because it's an enum where members has been added).

Then just detach your second windbg instance from the first one and close it. After this every sos command I have tried seems to be working fine.

2 thoughts on “Using SoS to debug 32-bit code in a 64-bit dump with WinDbg

  1. Hi Kasper 🙂
    I just came across your contribution to the wkhtml thingie which is nice but I turned to be a more linux guy these days (oh good old Windows 🙂

    What do you think it would take to rebuild the thing for Linux?
    A glimpse of a guidance would be highly appreciated!

    Thanks!
    Paul

  2. If you don't care that you need to have a X server running then I think you just need to tweak the build script. I think it can be made headless either by adding a dummy "console" Qt platform or tweaking QtWebKit to handle running headlessly

Leave a Reply

Your email address will not be published. Required fields are marked *