Debugging Production SharePoint Applications Wouter van Vugt Agenda • How .NET and the CLR work • Optimizing code and the effect on debuggers • Debugging third party code HOW .NET AND THE CLR WORK .NET Applications • Written in any language • Executed in a runtime called CLR – Shield code from hardware specifics • Java: One language, multi OS • .NET: Many languages, one OS (and Mono) – Allows various types of preprocessing of code OS CLR App Common Language Runtime Operation • Memory management • Thread synchronization • Error handling • Type Safety Security Execution • Code Access Security • Data Execution Prevention (OS) • Address Space Layout Randomization (OS) • Intermediate Language Type Safety • Type Safety – A pointer of a specific type can never point to an object which is not of that type! Car c = new Person() ‘Pointer type’ Pointer Object type – Checked at compile AND runtime! – Knowing the actual type enables • Reading its data Quite useful in debugging • Calling its functions Demo TRY AND CIRCUMVENT TYPE SAFETY Creating .NET Applications C#, C++, VB.NET, F#.... (40+) Compile Module PDB Link Assembly PDB Executing code • Assemblies contain mostly IL code – IL is the ‘Machine code’ for .NET – Compiled to native instructions at runtime through the JIT Compiler – Enough information remains to decompile back to source! Language richness compared Machine Code C# IL Executing code with JIT Compilation Console.WriteLine("Hi"); Console.WriteLine("There"); Console metadata static void WriteLine() JIT Compiler Address static void WriteLine(string) JIT Native Compiler Address Address Native CPU Instructions JIT Compiler -Lookup IL for method -Compile IL to native -Modify metadata to point to compiled code -Jump to compiled code Executing code with JIT Compilation Console.WriteLine("Hi"); Console.WriteLine("There"); Console metadata static void WriteLine() JIT Compiler Address static void WriteLine(string) Native Address Native CPU Instructions JIT Compiler -Lookup IL for method -Compile IL to native -Modify metadata to point to compiled code -Jump to compiled code Code optimization • Compile-time – Constant value folding – Remove Branch to next instruction and NOP instructions used to break on control flow, {, }, EndIf etc – Overflow checking –… • During JIT – – – – – Eliminate local variables Range check elimination Method inlining Tail call optimization Common subexpression elimination – Dead code elimination – Loop unrolling –… Running non optimized code • Breakpoints • Edit and continue C# Compiler – Variable Generation C# Compiler – Variable Generation Debug Release C# Compiler – Inserting NOP C# Compiler – Inserting NOP Debug Release C# Compiler – Branching C# Compiler – Branching Debug Release Demo COMPILE TIME OPTIMIZATIONS Just In Time Compilation • Transformation of MSIL to native x86 / x64 / ARM etc • Can optimize code – Mathematically ensured correctness • Takes a small performance hit during startup Compiler switch C# IL Code Quality JIT Native Code Quality /optimize- /debug- Unoptimized Optimized /optimize- /debug+ Unoptimized Unoptimized /optimize+ /debug+ Optimized Optimized NGEN.exe • JIT Compilation incurs a runtime cost • NGEN pre-compiles MSIL assemblies to machine code • Runs as a service in the background • Also used by the “.NET Runtime Optimization Service” JIT - Local variable elimination User user = GetUser(3); PrintUser(user); Before PrintUser(GetUser(3)); After JIT – Range check elimination static static static { for int[] _array = new int[10]; volatile int _i; void Main(string[] args) Before (int i = 0; i < _array.Length; ++i) _i += _array[i]; } static int[] _array = new int[10]; static volatile int _i; static void Main(string[] args) { int[] localRef = _array; for (int i = 0; i < localRef.Length; ++i) _i += localRef[i]; } After JIT – Method Inlining public class Program { public static int And(int first, int second) { return first & second; } static void Main(string[] args) { int i = And(5, 4); } } public class Program { static void Main(string[] args) { int i = 5 & 4; } } Before After JIT – Tail Call Optimization static void Main(string[] args) { TestTailCallOptimization(); } public static void TestTailCallOptimization() { string s = "Test"; TailCall1(s); } static void TailCall1(string s) { Console.WriteLine(s); TailCall2(s); } static void TailCall2(string s) { Console.WriteLine(s + s); } Loading non-precompiled assemblies • Native NGEN images are hard to debug – Remove the NGEN image C:\> NGEN uninstall MyAssembly – Or, prevent NGEN image from loading C:\> SET COMPLUS_ZAPDISABLE=1 Preventing JIT optimization • Creating debug builds – JIT prevented through compile time attributes [assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.Default)] • INI file MyAssembly.ini [.NET Framework Debugging Control] GenerateTrackingInfo=1 AllowOptimize=0 • In Visual Studio, on module load after attach Demo DEBUGGING OPTIMIZED CODE Debugging code • PDB files are as essential as code! • Breakpoints can do way more than break • Tracing is cheaper than debugging • IntelliTrace can run in production PDB Files • Contain vital debugging information • No PDB? Severely limited debugging experience! • Minimal investment: Symbol server • Managed PDB files contain – Source file names / line numbers – Local variable names – Alternate streams Used by TFS Symbol Servers • Central repository for storing debug symbols • File system based technology • Integrated into Team Foundation and Visual Studio Locating debug symbols MyAssembly.dll GUID MyAssembly.pdb Equal • PDB files are located – Same directory as module – Hardcoded path in module – Symbol server cache – Symbol server GUID Dumpbin.exe • Use to peek inside PE files Prevent loading all PDBs Visual Studio Source Server support • Allows Visual Studio to download relevant source files automatically from a repository. Configuring Symbol Locations PDB alternate streams • Used by TFS to store server path to sources Demo SYMBOL SERVERS, SOURCE SERVERS AND SOURCE INDEXING Working with break points Setting breakpoints on automatic properties • Use ‘Break at function’ and enter get_name Setting breakpoints on automatic properties • Inspect callstack / locals window Debugging third party code • Red Gate .NET Reflector PRO – Decompile assemblies into source code – Generate PDB file from assembly + source – Enables debugging third party code Enabling remote debugging • Run Remote Debugging x86 or x64 • Give permissions • Connect Demo DEBUGGING SHAREPOINT