Repository navigation
[cDAC] Map entry point to code start in GetMethodVarInfo; make ReJIT optional in IsVersionable - #135430
Conversation
…onal in IsVersionable GetMethodVarInfo computed codeOffset relative to the native-code entry point. With portable entry points the entry point is not the code start, so map it with IExecutionManager.GetDiagnosticCodeStartFromEntryPoint (the cDAC mirror of the runtime's GetDiagnosticCodeStartFromEntryPoint). IsVersionable required the ReJIT contract, which is only advertised with profiling support. Without it, native IsEligibleForReJIT is false, so treat a missing ReJIT contract as not ReJIT-eligible. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 5 pipeline(s). 11 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
Are you able to select the correct debug info with offset 0x2 - for example, as this API is being used here? |
…onal in IsVersionable Cherry-pick of dotnet#135430. GetMethodVarInfo maps the native code version's entry point with IExecutionManager.GetDiagnosticCodeStartFromEntryPoint, and IsVersionable treats a missing ReJIT contract as not ReJIT-eligible. This replaces the wasm-only GetMethodCodeOffset branch (and its unit test): WASM now takes the shared path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Not in general on WASM. The It works today only because unoptimized WASM scopes are method-wide (#133086 opens them in the first emitted block), so any offset inside the method selects them. A variable whose location changes mid-method, for example a parameter homed from its wasm local in the prolog, can select the wrong record. Fixing that needs either virtual-IP-space ranges from the producer or a virtual-IP → native-offset map. It's listed as a limitation on #133890. This PR doesn't change that: on WASM, the shared path now returns the same offset the wasm-specific path in #133890 did, and #133890 now uses this path instead. Note This comment was generated with GitHub Copilot. |
Makes sense, I’ll approve this for now then. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@rcj1 I had to commit again to merge main |
|
/ba-g failure is not related |
…rames (#136362) Independent of #136361 in code, but end-to-end testing on iOS needs #136361, otherwise in-app debugging never attaches. ## Summary With the cDAC as the in-app `IDacDbiInterface` on CoreCLR iOS, where Debug app code runs on the interpreter, the debugger never reported `Debugger.Break`. Two cDAC divergences from the native DAC cause this, one per commit. ### 1. Map entry point to code start when finding a native code version `CodeVersions_1.GetSpecificNativeCodeVersion` compared the MethodDesc native code slot with the code-block start. For interpreted methods the slot holds an `InterpreterPrecode` and the code block starts at the bytecode, so the two never matched. - `GetNativeCodeVersionForIP` returned an invalid handle. - `DebugInfo_1.GetMethodVarInfo` threw "No NativeCodeVersion found for native code …" (`0x80131509`). - `GetNativeCodeSequencePointsAndVarInfo` failed, the DBI abandoned the frame, and the stop was dropped. The fix maps the default and explicit versions' native code through `IExecutionManager.GetDiagnosticCodeStartFromEntryPoint` before comparing. That's the helper #135430 added for `GetMethodVarInfo`; it covers interpreter precodes and portable entry points. It matches the native DAC's `GetInterpreterCodeFromEntryPointIfPresent(NativeCodeVersion::GetNativeCode())` pattern. #135430 alone isn't enough, because the throw happens before its offset mapping. Tests and docs: - `CodeVersionsTests.GetNativeCodeVersion_Interpreted_MapsPrecodeToBytecode` (4 architectures). - The mock `AddCodeBlock` gets a default identity `GetDiagnosticCodeStartFromEntryPoint`. - `CodeVersions.md` pseudo-code updated. ### 2. Compute caller SP for interpreted frames like the native code manager `StackWalk_1.CallerStackPointer` backs `GetRuntimeFramePointer` on caller-SP architectures such as ARM64, and `GetFuncletRootId` (`fpParentOrSelf`). It always ran the OS unwinder, which has no unwind info for bytecode, so `fp`/`fpParentOrSelf` came back as the frame's own SP. For interpreter code it now uses the new `FrameHelpers.InterpreterCallerStackPointer`, which returns: - the parent `InterpMethodContextFrame`, including the zeroed root frame (`ip == NULL`) of an interpreter activation, or - the owning `InterpreterFrame` when there is no parent. This is the SP that native `VirtualUnwindInterpreterCallFrame` (eetwain.cpp) gives the caller context. The walker's own unwind path (`Next`) is unchanged. Tests and docs: - `StackWalkTests.CallerStackPointer_InterpretedFrame_IsParentInterpMethodContextFrame` and `StackWalkTests.CallerStackPointer_InterpretedFrameWithRootParent_IsRootFrameAddress`. - `StackWalk.md` updated. ## Validation - Unit tests (`Microsoft.Diagnostics.DataContractReader.Tests`): - **3,406/3,406** pass after commit 1, and **3,408/3,408** after commit 2. - Each new test fails without its own commit's product change and passes with it. - `Microsoft.Diagnostics.DataContractReader.Usage.Tests`: 4/4 after each commit. - **iOS Simulator** (iossimulator-arm64, interpreted Debug app, VS Code .NET MAUI F5 flow, `DOTNET_ENABLE_CDAC=1`, with #136361 applied): - `Debugger.Break` stops, and stepping, Locals and caller inspection all work. - A diagnosis-only trace compared each cDAC result with the legacy DAC for the same calls during the whole workflow: - `GetNativeCodeSequencePointsAndVarInfo`: **8/8 calls match** in HRESULT, variable count and sequence-point count; - `GetStackWalkCurrentFrameInfo`: **0 mismatches in 975 compared frame fields** (including `fp`, `fpParentOrSelf`, method token and MethodDesc, native start and offset, and context) across 288 frames, covering every frame token in the session. - Without these commits, the same scenario never reports `Debugger.Break`. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Two
IDebugInfo.GetMethodVarInfofixes for targets that use portable entry points, such as CoreCLR WebAssembly.GetMethodVarInfocode offsetcodeOffsetwas computed relative toICodeVersions.GetNativeCode, which is the method's entry point. On portable-entrypoint targets that is not the code start, so the offset was wrong. The entry point is now mapped withIExecutionManager.GetDiagnosticCodeStartFromEntryPoint(#134827), the cDAC mirror of the runtime'sGetDiagnosticCodeStartFromEntryPoint. It returns:Native
ClrDataAccess::GetMethodVarInfomaps only interpreter entry points (GetInterpreterCodeFromEntryPointIfPresent). The native DAC does not support wasm, so the R2R portable-entrypoint case has no native DAC behavior to compare against.IsVersionablewithout the ReJIT contractGetMethodVarInfo→GetNativeCodeVersionForIP→IsVersionablerequired theReJITcontract. The runtime advertises that contract only underPROFILING_SUPPORTED, which is off on wasm, soGetMethodVarInfothrewContractMissingExceptionthere. Wasm also lacksFEATURE_REJIT, so nativeIsEligibleForReJITis false. A missing contract is now treated as not ReJIT-eligible, usingTryGetContract.An alternative is to advertise
ReJITon wasm, withIsEnabled()returning false; I'm happy to switch if reviewers prefer that. Separately,CoreCLRContracts.ValidateForDataAccessstill requiresIReJIT, so on wasm the official DAC entry point would fail validation. That is not changed here and needs its own follow-up.Validation
./build.sh -s tools.cdactests -test: passed (Unit tests 3293/3293, DataGenerator 46/46, Usage 4/4).generate-docs.ps1 -Check: up to date.GetMethodVarInfo_CodeOffsetIsRelativeToDiagnosticCodeStart(theory: identity mapping, and an entry point mapped to a different code start).IsVersionable_ReJITContractOptional(theory: no ReJIT contract, ReJIT disabled, ReJIT enabled).GetDebugInfo_R2R_NoDebugInfoSection_ReturnsNullnow registersFeatureFlagsandPrecodeStubs, which the mapping requires.cv.GetNativeCode(ncvh)→GetMethodVarInfo_CodeOffset…(0x400000→0x80010100)fails withAssert.Equal._target.Contracts.ReJIT.IsEnabled()→IsVersionable_ReJITContractOptional(advertiseReJIT: False)fails withContractMissingException.0x41ADC1Cmaps to diagnostic start0x800104B3, andGetMethodVarInforeturns offset0x2. That is the same result as a wasm-only offset computation used in an earlier prototype. That target used a producer-side branch with variable debug info ([wasm] Preserve R2R variable debug information #133086); there is no automated test for this case.Note
This PR description was generated with GitHub Copilot.