From c08d7a9edad993c575218390583834ffe31dcd19 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Fri, 31 Jan 2025 13:46:48 +0500 Subject: [PATCH 1/4] Add instructions how to debug NativeAOT exceptions on the ARM64 --- docs/core/deploying/native-aot/diagnostics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/native-aot/diagnostics.md b/docs/core/deploying/native-aot/diagnostics.md index 805a405ec511a..990cb5a57d07b 100644 --- a/docs/core/deploying/native-aot/diagnostics.md +++ b/docs/core/deploying/native-aot/diagnostics.md @@ -62,7 +62,7 @@ You can launch a Native AOT-compiled executable under the Visual Studio debugger To set a breakpoint that breaks whenever an exception is thrown, choose the **Breakpoints** option from the **Debug > Windows** menu. In the new window, select **New > Function** breakpoint. Specify `RhThrowEx` as the Function Name and leave the Language option at **All Languages** (don't select C#). -To see what exception was thrown, start debugging (**Debug > Start Debugging** or F5), open the Watch window (**Debug > Windows > Watch**), and add following expression as one of the watches: `(S_P_CoreLib_System_Exception*)@rcx`. This mechanism leverages the fact that at the time `RhThrowEx` is called, the x64 CPU register RCX contains the thrown exception. You can also paste the expression into the Immediate window; the syntax is the same as for watches. +To see what exception was thrown, start debugging (`Debug` -> `Start Debugging` or `F5`), open the Watches window (`Debug` -> `Windows` -> `Watch`) and add following expression as one of the watches: `(S_P_CoreLib_System_Exception*)@rcx` on x64, or `(S_P_CoreLib_System_Exception*)x0` on ARM64. This leverages the fact that at the time `RhThrowEx` is called, the registers RCX and X0 contain the thrown exception, on x64 and ARM64, respectively. You can also paste the expression into the `Immediate Window`; the syntax is the same as for watches. ### Importance of the symbol file From 2b5cac09752991ac7a46c73aa038d6f1c522b747 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Sun, 2 Feb 2025 16:19:44 +0500 Subject: [PATCH 2/4] Update PR feedback --- docs/core/deploying/native-aot/diagnostics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/deploying/native-aot/diagnostics.md b/docs/core/deploying/native-aot/diagnostics.md index 990cb5a57d07b..9a97622432b49 100644 --- a/docs/core/deploying/native-aot/diagnostics.md +++ b/docs/core/deploying/native-aot/diagnostics.md @@ -51,7 +51,7 @@ After publishing, Native AOT applications are true native binaries. The managed The Native AOT compiler generates information about line numbers, types, locals, and parameters. The native debugger lets you inspect stack trace and variables, step into or over source lines, or set line breakpoints. -To debug managed exceptions, set a breakpoint on the `RhThrowEx` method, which is called whenever a managed exception is thrown. The exception is stored in the `rcx` or `x0` register. If your debugger supports viewing C++ objects, you can cast +To debug managed exceptions, set a breakpoint on the `RhThrowEx` method, which is called whenever a managed exception is thrown. The exception is stored in the first argument register that is rcx on x64 and x0 on Arm64. If your debugger supports viewing C++ objects, you can cast the register to `S_P_CoreLib_System_Exception*` to see more information about the exception. Collecting a [dump](../../diagnostics/dumps.md) file for a Native AOT application involves some manual steps in .NET 8. @@ -62,7 +62,7 @@ You can launch a Native AOT-compiled executable under the Visual Studio debugger To set a breakpoint that breaks whenever an exception is thrown, choose the **Breakpoints** option from the **Debug > Windows** menu. In the new window, select **New > Function** breakpoint. Specify `RhThrowEx` as the Function Name and leave the Language option at **All Languages** (don't select C#). -To see what exception was thrown, start debugging (`Debug` -> `Start Debugging` or `F5`), open the Watches window (`Debug` -> `Windows` -> `Watch`) and add following expression as one of the watches: `(S_P_CoreLib_System_Exception*)@rcx` on x64, or `(S_P_CoreLib_System_Exception*)x0` on ARM64. This leverages the fact that at the time `RhThrowEx` is called, the registers RCX and X0 contain the thrown exception, on x64 and ARM64, respectively. You can also paste the expression into the `Immediate Window`; the syntax is the same as for watches. +To see what exception was thrown, start debugging (**Debug > Start Debugging** or F5), open the Watch window (**Debug > Windows > Watch**), and add following expression as one of the watches: `(S_P_CoreLib_System_Exception*)@rcx` on x64, or `(S_P_CoreLib_System_Exception*)x0` on ARM64. This mechanism leverages the fact that at the time `RhThrowEx` is called, the x64 CPU register RCX or ARM64 register X0 contains the thrown exception, on x64 and ARM64, respectively. You can also paste the expression into the **Immediate Window**; the syntax is the same as for watches. ### Importance of the symbol file From 2ecb6a93d73ee6cde498f5af7fe0242cb488a745 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Sun, 2 Feb 2025 16:20:22 +0500 Subject: [PATCH 3/4] Mark registers in the code --- docs/core/deploying/native-aot/diagnostics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/deploying/native-aot/diagnostics.md b/docs/core/deploying/native-aot/diagnostics.md index 9a97622432b49..f1d3091a872c6 100644 --- a/docs/core/deploying/native-aot/diagnostics.md +++ b/docs/core/deploying/native-aot/diagnostics.md @@ -51,7 +51,7 @@ After publishing, Native AOT applications are true native binaries. The managed The Native AOT compiler generates information about line numbers, types, locals, and parameters. The native debugger lets you inspect stack trace and variables, step into or over source lines, or set line breakpoints. -To debug managed exceptions, set a breakpoint on the `RhThrowEx` method, which is called whenever a managed exception is thrown. The exception is stored in the first argument register that is rcx on x64 and x0 on Arm64. If your debugger supports viewing C++ objects, you can cast +To debug managed exceptions, set a breakpoint on the `RhThrowEx` method, which is called whenever a managed exception is thrown. The exception is stored in the first argument register that is `rcx` on x64 and `x0` on Arm64. If your debugger supports viewing C++ objects, you can cast the register to `S_P_CoreLib_System_Exception*` to see more information about the exception. Collecting a [dump](../../diagnostics/dumps.md) file for a Native AOT application involves some manual steps in .NET 8. From 3cf425b111544bac9c6cc1a64cf96d0bb428536c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 3 Feb 2025 08:21:22 +0100 Subject: [PATCH 4/4] Update docs/core/deploying/native-aot/diagnostics.md --- docs/core/deploying/native-aot/diagnostics.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/core/deploying/native-aot/diagnostics.md b/docs/core/deploying/native-aot/diagnostics.md index f1d3091a872c6..a8318c19d77fb 100644 --- a/docs/core/deploying/native-aot/diagnostics.md +++ b/docs/core/deploying/native-aot/diagnostics.md @@ -62,7 +62,14 @@ You can launch a Native AOT-compiled executable under the Visual Studio debugger To set a breakpoint that breaks whenever an exception is thrown, choose the **Breakpoints** option from the **Debug > Windows** menu. In the new window, select **New > Function** breakpoint. Specify `RhThrowEx` as the Function Name and leave the Language option at **All Languages** (don't select C#). -To see what exception was thrown, start debugging (**Debug > Start Debugging** or F5), open the Watch window (**Debug > Windows > Watch**), and add following expression as one of the watches: `(S_P_CoreLib_System_Exception*)@rcx` on x64, or `(S_P_CoreLib_System_Exception*)x0` on ARM64. This mechanism leverages the fact that at the time `RhThrowEx` is called, the x64 CPU register RCX or ARM64 register X0 contains the thrown exception, on x64 and ARM64, respectively. You can also paste the expression into the **Immediate Window**; the syntax is the same as for watches. +To see what exception was thrown, start debugging (**Debug > Start Debugging** or F5) and when the `RhThrowEx` breakpoint hits, open the Watch window (**Debug > Windows > Watch**), and add following expression as one of the watches: + +| | Expression | +|--------------------|---------------------------------------| +| x64 architecture | `(S_P_CoreLib_System_Exception*)@rcx` | +| Arm64 architecture | `(S_P_CoreLib_System_Exception*)@x0` | + +This mechanism leverages the fact that at the time `RhThrowEx` is called, the CPU register mentioned in the table contains the thrown exception. You can also paste the expression into the Visual Studio **Immediate Window**; the syntax is the same as for watches. ### Importance of the symbol file