A Debugging Approach to Windows RT

Recently I got a Surface with Windows RT. Needless to mention, it's wonderful!

I've figured out some quick facts about Windows RT by looking at the C:\Windows\system32\ntdll.dll from Windows RT:

  • A complete NT (instead of WINCE) kernel and almost a full stack of Windows operating system.
  • Almost the same PE/COFF structure as x86.
  • Using ARM's "non classic RISC style" Thumb-2 instruction set (pImageNtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_ARMNT), which has great code density, and in turn gives smaller binary and less memory pressure.

I've never had a chance to debug Thumb-2 code before, so I've listed the things I need to grasp:

  • Fundamental ARM architecture and Thumb-2 instructions.
  • ABI (Application Binary Interface), calling convention and exception handling mechanism.
  • Programming and debugging.

Programming

Although Visual Studio 2012 doesn't have an ARM version, it does included the x86 cross toolchain which allows targeting ARM architecture, which can be found from %ProgramFiles(x86)%\Microsoft Visual Studio 11.0\VC\bin\x86_arm\ . By setting the correct environment variable (INCLUDE, LIB, LIBPATH, PATH) we can generate ARM module smoothly.

 int main()
{
  return 0;
}
 C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\x86_arm>cl.exe /link /NODEFAULTLIB /ENTRY:main test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.51106.1 for ARM Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 11.00.51106.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
/machine:arm
/NODEFAULTLIB
/ENTRY:main
test.obj

By default Visual Studio doesn't allow generating native ARM binary, and the restriction was from a MSBuild property named WindowsSDKDesktopARMSupport, by setting this property to true I could target ARM native without an issue.

Another problem is that Windows SDK doesn't have the ARM version of import libraries, which means we don't have files like gdi32.lib and shell32.lib. The solution would be creating one either by writing a DEF file, or creating a stub module. Since we can get the ARM version of DLLs from Windows RT, it is easy to dump the export directory and create DEF file automatically, as long as the DLLs we use is not exporting mangled name (otherwise I would prefer to use stub module approach).

This is what I got while running my very first hello.exe on Windows RT :)

For pure managed code programming, the .NET runtime in Surface RT comes with the standard C# compiler:

 class Hello
{
  static void Main()
  {
  }
}
 C:\Users\Reiley\Desktop>" %WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe" /noconfig /debug+ /platform:anycpu hello.cs
Microsoft (R) Visual C# Compiler version 4.0.30319.17929 
for Microsoft (R) .NET Framework 4.5
Copyright (C) Microsoft Corporation. All rights reserved.

And this time I got something worse:

After changing the compiler flag to target ARM instead of AnyCPU, it became better and I was again greeted with the "Windows cannot verify the digital signature ..." dialog.

 C:\Users\Reiley\Desktop>" %WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe" /noconfig /debug+ /platform:arm hello.cs

Debugging

The x86 and amd64 version of WinDBG both support various architectures including ARM Thumb-2, which means you can open dump files from a PC. This is a good place to get started, and actually I copied notepad.exe from Surface to my PC and used cdb.exe -z notepad.exe to familiar myself with the ARM PE structure and disassembly.

There is no ARM version of WinDBG available for public download. Also ntsd.exe is no longer shipped as part of the Windows since Vista.

Visual Studio 2012 comes with a great debugger, together with a fantastic remote debugging agent. Jason Zander already explained how to setup remote debugging from his great article "What you need to know about developing for Windows on ARM". I'll just put a conclusion here:

  1. Visual Studio 2012 doesn't have ARM version, in fact only x86 version is available.
  2. Visual Studio 2012 supports remote kernel debugging, however there is no direct way to enable kernel debugging on Windows RT device.
  3. Visual Studio 2012 comes with an ARM version of remote debugging agent, which makes it possible to do user mode debugging on nearly all processes. To unleash the power, run remote debugging agent (msvsmon) as a service under an administrator account.
  4. User mode debugging on Windows RT is powerful enough that you can do whatever hack you like.

 

(to be continued...)