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.

Continue reading

Lessons learned from working with the Windows shell namespace

Lessons learned while writing PSShellProvider:

  • Barring null-characters (well it would break things) there is absolutely no limitations on what a display name might contain – even display names for parsing. E.g. the display name for parsing for my smartphone connected as an MTP device is:

    This gives it a full display name for parsing (what I'm calling "parse path") of:


    Ugh… In this case the full path can still be parsed because it sees the first backslash as the delimiter and the IShellFolder handler for "This PC" recognizes the rest of it. But what if the display name ended with a backslash instead?

  • The Desktop folder is the root of the shell namespace, but the empty string parses into the "This PC" virtual folder. Wat?
  • The Desktop folder is the root of the shell namespace, but if you ask it what its desktop absolute parsing path is then it gives you the filesystem path to the user's Desktop folder in the filesystem, e.g.

    Parsing this display name obviously doesn't give you the virtual Desktop folder which contains This PC and other virtual folders, but the user's Desktop folder in the filesystem instead. Also by this logic the (virtual) Desktop folder is a descendant of itself.

  • The same thing as the point above happens with other special folders as well, however this isn't a problem for most of them as they have a 1-to-1 correspondence between the virtual folder and the filesystem folder. Example listing special folders from the desktop:
    DisplayName      ParseName                                DesktopAbsoluteParsePath
    -----------      ---------                                ------------------------
    This PC          ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}
    Recycle Bin      ::{645FF040-5081-101B-9F08-00AA002F954E} ::{645FF040-5081-101B-9F08-00AA002F954E}
    Control Panel    ::{26EE0668-A00A-44D7-9371-BEB064C98683} ::{26EE0668-A00A-44D7-9371-BEB064C98683}
    poizan           ::{59031A47-3F72-44A7-89C5-5595FE6B30EE} C:\Users\poizan
    Libraries        ::{031E4825-7B94-4DC3-B131-E946B44C8DD5} ::{031E4825-7B94-4DC3-B131-E946B44C8DD5}
    Control Panel    ::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0} ::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}
    Homegroup        ::{B4FB3F98-C1EA-428D-A78A-D1F5659CBA93} ::{B4FB3F98-C1EA-428D-A78A-D1F5659CBA93}
    Network          ::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C} ::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}
    OneDrive         ::{018D5C66-4533-4307-9B53-224DE2ED1FE6} C:\Users\poizan\OneDrive
    Dropbox          ::{E31EA727-12ED-4702-820C-4B6445F28E1A} C:\Users\poizan\Dropbox

    And here from This PC:

    DisplayName       ParseName                                 DesktopAbsoluteParsePath
    -----------       ---------                                 ------------------------
    Downloads         ::{088E3905-0323-4B02-9826-5D99428E115F}  C:\Users\poizan\Downloads
    Pictures          ::{24AD3AD4-A569-4530-98E1-AB02F9417AA8}  C:\Users\poizan\Pictures
    Music             ::{3DFDF296-DBEC-4FB4-81D1-6A3438BCF4DE}  C:\Users\poizan\Music
    Desktop           ::{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}  C:\Users\poizan\Desktop
    Documents         ::{D3162B92-9365-467A-956B-92703ACA08AF}  C:\Users\poizan\Documents
    Videos            ::{F86FA3AB-70D2-4FC7-9C99-FCBF05467F3A}  C:\Users\poizan\Videos
    TVMOBiLi.dy       uuid:4f592dcd-11cb-422f-0b50-8064792d2d2d ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\uuid:4f592dcd-11cb-422f-0b50-8064792d2d2d
    Acer (C:)         C:                                        C:\
    DVD RW Drive (D:) D:                                        D:\
    BD-ROM Drive (F:) F:                                        F:\
  • The display names of files in the filesystem are always short (8.3) names given that those exists. This is true for all the variants of the display name. This seems weird as it certainly isn't how they are shown in Windows Explorer and normal shell views. I couldn't find any mention of this on google either – maybe there is some flag that one can use to change the behaviour? Or something in the manifest file (which wouldn't help in my case as I can't control PowerShell's manifest). Barring a better solution, the best way to get the real name is probably to get the file system path and then get the long path using GetLongPathNameSHGetFileInfo should be able to give us the long name directly from the pidl, but it's limited to MAX_PATH length.

Which exceptions do you get from different IO errors in .NET?



Action Exception HResult Other error code
FileMode.CreateNew on existing file System.IO.IOException -2147024816 (0x80070050)
Opening a file with access incompatible with the share mode of an existing handle System.IO.IOException -2147024864 (0x80070020)
Opening a non-existing file in a directory even without read or listing access System.IO.FileNotFoundException -2147024894 (0x80070002)
Any file mode on directory System.UnauthorizedAccessException -2147024891 (0x80070005)
Opening a read-only file for writing System.UnauthorizedAccessException -2147024891 (0x80070005)
Creating a file in a directory without write access System.UnauthorizedAccessException -2147024891 (0x80070005)

What assembly is this RuntimeAssembly?

Say that you are debugging a .NET application in windbg and happen to have a System.Reflection.RuntimeAssembly (the actual implementation of System.Reflection.Assembly) and you want to find out which assembly it actually references. You could try dumping the object (i'm using the sosex extension here):

0:004> !mdt -r 05f7868c
05f7868c (System.Reflection.RuntimeAssembly)
_ModuleResolve:NULL (System.Reflection.ModuleResolveEventHandler)
m_fullname:NULL (System.String)
m_syncRoot:NULL (System.Object)
m_assembly:0eaa4ba8 (System.IntPtr)
m_flags:0x0 (ASSEMBLY_FLAGS_UNKNOWN) (System.Reflection.RuntimeAssembly+ASSEMBLY_FLAGS)

That wasn't very helpful. The object is just a thin wrapper around the native object pointed to by m_assembly. So what is this object? This is what it looks like:

0:004> dd 0eaa4ba8 L30
0eaa4ba8 692addec 014ad1b8 0f7307d8 00000000
0eaa4bb8 0fd49ca4 0000000c 0987de05 00000000
0eaa4bc8 00000007 00000001 00000000 00000000
0eaa4bd8 00000000 00000000 6d079b44 0987de01
0eaa4be8 0f842758 00000000 005508d0 00000002
0eaa4bf8 00000000 00000000 00000000 00000001
0eaa4c08 00000000 00000005 0eaa4ba8 f149a627
0eaa4c18 191e1826 33a15c96 1fa78d20 00000000
0eaa4c28 00000000 00000000 00000101 00000000
0eaa4c38 36664efa 8c001f00 692addec ...

A good trick is to check whether the first value is a vtable pointer:

0:004> ln 692addec
(692addec) clr!DomainAssembly::`vftable' ...

So apparently the object is a DomainAssembly object, whatever that is (you can find some of these classes in the Rotor source, but the structure of them are vastly different). Using this trick combined with the !mln sosex command we find:

692addec: clr!DomainAssembly::`vftable'
014ad1b8: -> to clr!AppDomain
0f7307d8: -> to clr!PEAssembly
0fd49ca4: -> to clr!EditAndContinueModule
0987de05: Heap Object: 09877108[System.Object[]]
offset 00006cfd
0987de04 -> RuntimeModule (05f78868) : m_runtimeAssemblt = 05f7868c
6d079b44: not a pointer
0987de01: Heap Object: 09877108[System.Object[]]
offset 00006cf9
0987de01 -> RuntimeAssembly (05f7868c)
0f842758: -> to clr!AssemblySecurityDescriptor
0eaa4ba8: -> this
f149a627: not a pointer
191e1826: not a pointer
33a15c96: not a pointer
1fa78d20: not a pointer
36664efa: not a pointer
8c001f00: not a pointer

692addec: start of next clr!DomainAssembly object...

The PEAssembly object:

0:004> dd 0f7307d8 L100
0f7307d8 692e2a64 0f5cb928 0f5cc828 00000000
692e2a64: vtable (clr!PEAssembly::`vftable')
0f5cb928: ???
0f5cc828: ??
0f7307e8 00000001 00000001 0149fc38 00000000
0149fc38: -> to clr!MDInternalRO
0f7307f8 00000000 00000000 00000000 00000000
0f730808 0f5b1340 00000006 00000000 00002002
0f5b1340: ??
0f730818 00000000 00000000 00000000 00000000
0f730828 ffffffff ffffffff 00000000 00000000
0f730838 00000000 020007d0 c0000000 00000000
020007d0: not a pointer
0f730848 00000000 00000000 0ea0b930 0f722e80
0ea0b930: -> to clr!CAssemblyName
0f722e80: -> to clr!CAssembly
0f730858 00000000 00000001 00000000 00000000
0f730868 00000000 00000002 00000000 00000001
0f730878 35f26672 88001820 692e2a64 00000000
35f26672: not a pointer
88001820: not a pointer
692e2a64: vtable pointer for next PEAssembly

CAssemblyName? That sounds promising, right?

0:004> dd 0ea0b930
0ea0b930 692b3210 692de934 454d414e 00000005
0ea0b940 504f5250 00000000 00000000 00000000
0ea0b950 00000000 00000000 00000000 0f722a58


0:004> du 0f722a58
0f722a58 "AxInterop.AcroPDFLib"

There was the name. And we had a pointer to the AppDomain earlier, so that should be sufficient to uniquely identify the assembly. I haven't figured out where the actual assembly or module objects as used by !DumpAssembly and !DumpModule resides, but they are probably somewhere in there (the modules are CModule objects, the assembly objects starts with a null pointer, so I couldn't tell the C++ class from that).

isapi filters and unicode urls

If you write a custom isapi filter then you have several ways to get the url, the difference between them being not exactly well documented (actually it seems that no one has even bothered updating the documentation since IIS 6.0). So I did a couple of tests with IIS 8.0. Here is what I could see when getting a SF_NOTIFY_PREPROC_HEADERS notification. pfc is the HTTP_FILTER_CONTEXT* and pHeaders is pvNotification cast into HYYP_FILTER_PREPROC_HEADERS*.

  • pHeaders->GetHeader(pfc, "URL", buf, &size)
    This is the complete raw url (as char array) as requested by the client. For example requesting


    results in buf containing

  • pfc->GetServerVariable(pfc, "URL", buf, &size)
    This contains the decoded path part of the requested url – also as a char array. This is probably encoded in the system ANSI Code Page (ACP). Characters not present in the ACP are replaced with '?'. For example requesting the above url results in buf containing


    Note that according to this the server variable URL shouldn't even be available in SF_NOTIFY_PREPROC_HEADERS. Apparently it is.

  • pfc->GetServerVariable(pfc, "UNICODE_URL", buf, &size)
    This is the same as above except that buf now contains a wchar_t array. Characters outside BMP seems to be correctly handled as a surrogate pair. So with the request from earlier buf will contain (as an UTF-16LE string):

  • pHeaders->GetHeader(pfc, "UNICODE_URL", buf, &size)
    As one would likely expect this doesn't exists. The call returns ERROR_INVALID_PARAMETER.

Yeah right Maple…



For the non-mathsy people: cot is defined as cos/sin, so f1 and f2 should represent the same function – as Maple also confirms on the line simplify(f1-f2) – and yet it somehow manages to get different results for what should be the same integral. The correct result is the second one of them. I should note that evaluating the integrals numerically yields the same result for both to within the accuracy used.

Fixing frequent freezing of Wasteland 1 when using mouse

UPDATE: According to inXile this fix will probably be incorporated into the next patch.

UPDATE2: This has been incorporated into patch 2.

Wasteland (the original) has a problem where it randomly freezes after playing for some time.
From the known issues FAQ:

The game freeze frequently.
o This is a heritage issue which may be circumvented by using only the keyboard to control the game.


In general, fixing legacy issues is a quasi-impossibility as the original is not buildable.

I'm not completely sure about what they mean by "not buildable", but frankly I would rather that inXile focus on T:ToN and Wasteland 2 than wasting resources on fixing legacy code from 25 years ago. However nothing prevents me from "wasting" resources on fixing 25 year old dos games. So I took it upon myself to localize and fix the issue.

The short version is this: find rom\DATA\WLA.BIN in your steamapps/GoG folder and open it in your favourite hex editor, go to offset 0E5E where it says "77 1F" and replace with "EB 1F". The long version below explains how I figured this out, and probably requires a good understanding of x86 assembler and the PC platform to read.
Continue reading

Reading raw attribute constructor data

Disassembling a custom attribute gives you a blob of raw bytes – what do they mean? Here is an example from the output from ildasm:
[code lang="cil"]
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = (
01 00 04 49 74 65 6d 00 00
) // …Item..
This represents a DefaultMemberAttribute("Item") which is autgenerated by C# when your class has an indexer. The word "Item" is definitely in there – but what does the rest of the data mean? A google search doesn't give any useful answer from what I could find. I ended up looking in the Ecma Standard (page 267). This diagram gives an overview of the structure:

The prolog is always 0x0010 and little-endian encoded. The FixedArgs are the arguments to the constructor and the NamedArgs are properties. A string is encoded as a SerString, which is a single byte length called a PackedLen followed by a UTF8 string. NumNamed is also a little-endian encoded integer containing the number of properties being set (named arguments).

So in this case the data can be broken down as:

01 00: The Prolog (0x0010 in little-endian)
04: The string is 4 characters long
49 74 65 6d: "Item"
00 00: We have 0 properties

Stupid Hack: Add / Remove only property in C#

UPDATE: The screenshot below was lost to the big /dev/null in a server move, so you have to use your imagination.

Can you make a property in C# that you can only add to and remove from? That is what an event does, but that only works with delegates. You can (ab)use an implicit conversion to get something like this:
[code lang="csharp"]

class Foo
public delegate void FooDelegate();
public string Message { get; set; }

public Foo(string message)
Message = message;

public static implicit operator FooDelegate(Foo foo)
return foo.Dummy;

private void Dummy() { }

class Bar
public List FooList { get; private set; }

public event Foo.FooDelegate Foos

public Bar()
FooList = new List();
Using it:
[code lang="csharp"]
static void Main(string[] args)
Bar bar = new Bar();
bar.Foos += new Foo("Hello, World!");
bar.Foos += new Foo("LOL!");
foreach (Foo foo in bar.FooList)
It works – I wouldn't recommend using it in production code though… Maybe more interresting is what would happen if we modified the CIL for an event to accept a non delegate type. Well let's try it and see what happens!

The original C# code:
[code lang="csharp"]
public class EventTester
private List testList = new List();
public List TestList { get { return testList; } }
public event Action TestEvent
Relevant parts of the generated CIL code:
[code lang="cil"]
.method public hidebysig specialname
instance void add_TestEvent (
class [mscorlib]System.Action 'value'
) cil managed
// Method begins at RVA 0x2068
// Code size 15 (0xf)
.maxstack 8

IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.List`1 EventTest.EventTester::testList
IL_0007: ldarg.1
IL_0008: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0)
IL_000d: nop
IL_000e: ret
} // end of method EventTester::add_TestEvent

.method public hidebysig specialname
instance void remove_TestEvent (
class [mscorlib]System.Action 'value'
) cil managed
// Method begins at RVA 0x2078
// Code size 15 (0xf)
.maxstack 8

IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.List`1 EventTest.EventTester::testList
IL_0007: ldarg.1
IL_0008: callvirt instance bool class [mscorlib]System.Collections.Generic.List`1::Remove(!0)
IL_000d: pop
IL_000e: ret
} // end of method EventTester::remove_TestEvent

// Events
.event [mscorlib]System.Action TestEvent
.addon instance void EventTest.EventTester::add_TestEvent(class [mscorlib]System.Action)
.removeon instance void EventTest.EventTester::remove_TestEvent(class [mscorlib]System.Action)
Let us replace "System.Action" with "System.Object" and see what happens. Running ilasm:

C:\Users\poizan\Documents\Visual Studio 2010\Projects\Test>ilasm /DLL

Microsoft (R) .NET Framework IL Assembler.  Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling ''  to DLL --> 'EventTest.dll'
Source file is ANSI

Assembled method EventTest.EventTester::get_TestList
Assembled method EventTest.EventTester::add_TestEvent
Assembled method EventTest.EventTester::remove_TestEvent
Assembled method EventTest.EventTester::.ctor
Creating PE file

Emitting classes:
Class 1:        EventTest.EventTester

Emitting fields and methods:
Class 1 Fields: 1;      Methods: 4;
Resolving local member refs: 7 -> 7 defs, 0 refs, 0 unresolved

Emitting events and properties:
Class 1 Events: 1;      Props: 1;
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

So far so good. Let us try to use it:
[code lang="csharp"]
class Program
static void Main(string[] args)
EventTester et = new EventTester();
et.TestEvent += "Hello, World!";
et.TestEvent += "Magic!";
foreach (string s in et.TestList.OfType())
It builds successfully. And running it:

 And that is one more thing the C# compiler supports just fine but refuses to create.