먼저이 질문의 길이에 대해 사과드립니다.
나는 IronScheme 의 저자입니다 . 최근에는 ‘기본’.NET 디버거를 사용할 수 있도록 적절한 디버그 정보를 생성하기 위해 열심히 노력하고 있습니다.
이것이 부분적으로 성공적 이었지만, 나는 이빨 문제가 발생했습니다.
첫 번째 문제는 스테핑과 관련이 있습니다.
Scheme은 표현 언어이기 때문에 문장 또는 라인 기반의 주요 .NET 언어와 달리 모든 것이 괄호로 묶이는 경향이 있습니다.
원래 코드 (스키마)는 다음과 같습니다.
(define (baz x)
(cond
[(null? x)
x]
[(pair? x)
(car x)]
[else
(assertion-violation #f "nooo" x)]))
나는 의도적으로 개행에 각 표현을 배치했습니다.
방출 된 코드는 ILSpy를 통해 C #으로 변환됩니다.
public static object ::baz(object x)
{
if (x == null)
{
return x;
}
if (x is Cons)
{
return Builtins.Car(x);
}
return #.ironscheme.exceptions::assertion-violation+(
RuntimeHelpers.False, "nooo", Builtins.List(x));
}
보다시피, 매우 간단합니다.
참고 : C #에서 코드가 조건식 (? :)으로 변환 된 경우 전체 단계는 하나의 디버그 단계 일 뿐이므로 명심하십시오.
다음은 소스 및 줄 번호가있는 IL 출력입니다.
.method public static object '::baz'(object x) cil managed
{
// Code size 56 (0x38)
.maxstack 6
.line 15,15 : 1,2 ''
//000014:
//000015: (define (baz x)
IL_0000: nop
.line 17,17 : 6,15 ''
//000016: (cond
//000017: [(null? x)
IL_0001: ldarg.0
IL_0002: brtrue IL_0009
.line 18,18 : 7,8 ''
//000018: x]
IL_0007: ldarg.0
IL_0008: ret
.line 19,19 : 6,15 ''
//000019: [(pair? x)
.line 19,19 : 6,15 ''
IL_0009: ldarg.0
IL_000a: isinst [IronScheme]IronScheme.Runtime.Cons
IL_000f: ldnull
IL_0010: cgt.un
IL_0012: brfalse IL_0020
IL_0017: ldarg.0
.line 20,20 : 7,14 ''
//000020: (car x)]
IL_0018: tail.
IL_001a: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_001f: ret
IL_0020: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_0025: ldstr "nooo"
IL_002a: ldarg.0
IL_002b: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
//000021: [else
//000022: (assertion-violation #f "nooo" x)]))
IL_0030: tail.
IL_0032: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_0037: ret
} // end of method 'eval-core(033)'::'::baz'
참고 : 디버거가 단순히 전체 메서드를 강조 표시하지 못하게하기 위해 메서드 입력 지점을 1 열 너비로 만듭니다.
보시다시피 각 표현식은 줄에 올바르게 매핑됩니다.
이제 스테핑 문제 (VS2010에서 테스트되었지만 VS2008에서 동일 / 유사한 문제) :
이들은 IgnoreSymbolStoreSequencePoints
적용되지 않습니다.
- null 인수로 baz를 호출하면 올바르게 작동합니다. (null? x) 다음에 x가옵니다.
- Cons arg를 사용하여 baz를 호출하면 올바르게 작동합니다. (null? x), (pair? x), (car x).
- 다른 인수와 함께 baz를 호출하면 실패합니다. (null? x), (pair? x), (car x), (어설 션 위반 …)
신청할 때 IgnoreSymbolStoreSequencePoints
(권장) :
- null 인수로 baz를 호출하면 올바르게 작동합니다. (null? x) 다음에 x가옵니다.
- Cons arg로 baz를 호출하면 실패합니다. (null? x) 그리고 (pair? x).
- 다른 인수와 함께 baz를 호출하면 실패합니다. (null? x), (pair? x), (car x), (어설 션 위반 …)
또한이 모드에서 (여기에 표시되지 않은) 일부 줄이 잘못 강조 표시되고 1만큼 줄어 듭니다.
다음은 원인이 될 수있는 몇 가지 아이디어입니다.
- Tailcalls는 디버거를 혼동합니다
- 겹치는 위치 (여기에 표시되지 않음)는 디버거를 혼동합니다 (브레이크 포인트를 설정할 때 매우 잘 수행됨)
- ????
두 번째이지만 심각한 문제는 디버거가 경우에 따라 중단 점을 중단 / 히트하지 못하는 것입니다.
디버거를 올바르게 (및 구성 적으로) 깨뜨리는 유일한 방법은 메소드 진입 점입니다.
IgnoreSymbolStoreSequencePoints
적용하지 않으면 상황이 조금 나아 집니다.
결론
VS 디버거가 평범한 버그 일 수 있습니다.
참고 문헌 :
업데이트 1 :
Mdbg는 64 비트 어셈블리에서 작동하지 않습니다. 그래서 밖으로입니다. 더 이상 테스트 할 32 비트 시스템이 없습니다. 업데이트 : 이것이 큰 문제는 아니라고 확신합니다. 누구든지 수정 했습니까? 편집 : 네, 어리석은, x64 명령 프롬프트에서 mdbg를 시작하십시오 🙂
업데이트 2 :
C # 앱을 만들고 회선 정보를 해부하려고했습니다.
나의 발견 :
brXXX
지시가 끝나면 시퀀스 포인트가 필요합니다 (유효하지 않은 경우 ‘#line hidden’이라고도 함nop
).brXXX
지시 하기 전에 ‘#line hidden’과 a를 내 보냅니다nop
.
이것을 적용해도 문제가 해결되지는 않습니다 (단독?).
그러나 다음을 추가하면 원하는 결과가 나옵니다. 🙂
- 다음
ret
에 ‘#line hidden’과 a을 내 보냅니다nop
.
IgnoreSymbolStoreSequencePoints
적용되지 않은 모드를 사용하고 있습니다 . 적용 할 때 일부 단계는 여전히 건너 뜁니다. (
위의 적용했을 때의 IL 출력은 다음과 같습니다.
.method public static object '::baz'(object x) cil managed
{
// Code size 63 (0x3f)
.maxstack 6
.line 15,15 : 1,2 ''
IL_0000: nop
.line 17,17 : 6,15 ''
IL_0001: ldarg.0
.line 16707566,16707566 : 0,0 ''
IL_0002: nop
IL_0003: brtrue IL_000c
.line 16707566,16707566 : 0,0 ''
IL_0008: nop
.line 18,18 : 7,8 ''
IL_0009: ldarg.0
IL_000a: ret
.line 16707566,16707566 : 0,0 ''
IL_000b: nop
.line 19,19 : 6,15 ''
.line 19,19 : 6,15 ''
IL_000c: ldarg.0
IL_000d: isinst [IronScheme]IronScheme.Runtime.Cons
IL_0012: ldnull
IL_0013: cgt.un
.line 16707566,16707566 : 0,0 ''
IL_0015: nop
IL_0016: brfalse IL_0026
.line 16707566,16707566 : 0,0 ''
IL_001b: nop
IL_001c: ldarg.0
.line 20,20 : 7,14 ''
IL_001d: tail.
IL_001f: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_0024: ret
.line 16707566,16707566 : 0,0 ''
IL_0025: nop
IL_0026: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_002b: ldstr "nooo"
IL_0030: ldarg.0
IL_0031: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
IL_0036: tail.
IL_0038: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_003d: ret
.line 16707566,16707566 : 0,0 ''
IL_003e: nop
} // end of method 'eval-core(033)'::'::baz'
업데이트 3 :
위의 ‘반 고정’에 문제가 있습니다. Peverify는 nop
이후 로 인한 모든 방법의 오류를보고합니다 ret
. 나는 문제를 정말로 이해하지 못한다. 방법을 수 nop
후 휴식 검증 ret
. 그것은 코드가 아닌 것을 제외하고는 죽은 코드와 같습니다 … 아, 실험은 계속됩니다.
업데이트 4 :
집으로 돌아와서 VS2008에서 실행되는 ‘확인할 수없는’코드를 제거했는데 상황이 훨씬 나빠졌습니다. 적절한 디버깅을 위해 검증 할 수없는 코드를 실행하는 것이 답이 될 수 있습니다. ‘릴리스’모드에서 모든 출력은 여전히 검증 가능합니다.
업데이트 5 :
나는 이제 내 생각이 유일하게 실행 가능한 옵션이라고 결정했다. 생성 된 코드를 확인할 수는 없지만 아직의 코드를 찾지 못했습니다 VerificationException
. 이 시나리오에서 최종 사용자에게 어떤 영향을 줄지 모르겠습니다.
보너스로 두 번째 문제도 해결되었습니다. 🙂
여기에 내가 끝낸 것에 대한 작은 스크린 캐스트 가 있습니다. 브레이크 포인트에 도달하고 적절한 스테핑 (입 / 출력 / 오버) 등을 수행합니다.
그러나 나는 여전히 이것을하는 방법으로 이것을 받아들이지 않고 있습니다. 그것은 나에게 지나치게 해킹을 느낀다. 실제 문제에 대한 확인이 있으면 좋을 것입니다.
업데이트 6 :
VS2010에서 코드를 테스트하기 위해 변경 했으므로 몇 가지 문제가있는 것 같습니다.
첫 번째 통화는 이제 올바르게 진행되지 않습니다. (어설 션 위반 …)이 발생했습니다. 다른 경우에는 잘 작동합니다.일부 오래된 코드는 불필요한 위치를 방출했습니다. 코드를 제거하고 예상대로 작동합니다. 🙂- 더 심각하게는 프로그램의 두 번째 호출에서 중단 점이 실패합니다 (메모리 내 컴파일 사용, 파일로 어셈블리 덤프는 중단 점이 다시 만족스러운 것으로 보입니다).
이 두 경우 모두 VS2008에서 올바르게 작동합니다. 주요 차이점은 VS2010에서 전체 응용 프로그램이 .NET 4 용으로 컴파일되고 VS2008에서 .NET 2로 컴파일된다는 것입니다. 둘 다 64 비트를 실행합니다.
업데이트 7 :
언급했듯이 mdbg가 64 비트에서 실행되었습니다. 불행히도 프로그램을 다시 실행하면 중단되지 않는 중단 점 문제가 있습니다 (이것은 다시 컴파일되므로 동일한 어셈블리를 사용하지 않고 여전히 동일한 소스를 사용함을 의미합니다).
업데이트 8 :
나는 한 버그를 제출 중단 점 문제에 관한 MS Connect 사이트에서.
업데이트 : 수정
업데이트 9 :
오랫동안 생각한 후에 디버거를 행복하게 만드는 유일한 방법은 SSA를 수행하는 것처럼 보이므로 모든 단계를 격리하고 순차적으로 수행 할 수 있습니다. 나는이 개념을 아직 증명하지 못했다. 그러나 논리적 인 것 같습니다. 분명히 SSA에서 temp를 정리하면 디버깅이 중단되지만 전환하기 쉽고 오버 헤드가 많지 않습니다.
답변
Visual Studio Debugger 팀의 엔지니어입니다.
내가 틀렸다면 수정하십시오.하지만 남은 유일한 문제는 PDB에서 .NET 4 동적 컴파일 기호 형식으로 전환 할 때 일부 중단 점이 누락되었다는 것입니다.
문제를 정확하게 진단하려면 재현이 필요할 수 있지만 다음은 도움이 될만한 참고 사항입니다.
- 비 관리자로 실행 가능한 VS (2008+)
- 두 번째로 항상 심볼이로드됩니까? 예외를 통해 침입하거나 System.Diagnostic.Debugger.Break ()를 호출하여 테스트 할 수 있습니다.
- 심볼이로드되었다고 가정하면 보내실 수있는 재현이 있습니까?
- 가능한 차이점은 동적 컴파일 코드의 기호 형식이 .NET 2 (PDB 스트림)와 .NET 4 (IL DB라고 부르는 것입니다)와 100 % 다르다는 것입니다.
- 바로 ‘잡음’소리. 아래의 암시 적 시퀀스 포인트 생성 규칙을 참조하십시오.
- 실제로 다른 라인에서 물건을 방출 할 필요는 없습니다. 기본적으로 VS는 컴파일러 작성기로서 ‘기호 문’의 의미를 정의하는 ‘기호 문’을 단계적으로 수행합니다. 따라서 각 표현식이 심볼 파일에서 별도의 것이기를 원한다면 제대로 작동합니다.
JIT는 다음 규칙에 따라 암시 적 시퀀스 포인트를 만듭니다. 1. IL nop 명령어 2. IL 스택 빈 포인트 3. 호출 명령어 바로 다음의 IL 명령어
문제를 해결하기 위해 repro가 필요한 경우 연결 버그를 신고하고 해당 매체를 통해 파일을 안전하게 업로드 할 수 있습니다.
최신 정보:
이 문제가 발생하는 다른 사용자에게 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27543 에서 Dev11 개발자 미리보기를 시도 하고 의견 을 보내 주시기 바랍니다 . (4.5 대상)
업데이트 2 :
Leppie는 http://www.microsoft.com/visualstudio/11/en-us/downloads(http://www.microsoft.com/visualstudio/11/en-us/downloads) 에있는 Dev11 베타 버전 에서 해당 버그를 수정했습니다 . com / VisualStudio / feedback / details / 684089 / .
감사,
누가
답변
나는 SharpDevelop 디버거 팀의 엔지니어입니다 🙂
문제를 해결 했습니까?
SharpDevelop에서 디버깅을 시도 했습니까? .NET에 버그가 있으면 해결 방법을 구현해야하는지 궁금합니다. 이 문제를 알지 못합니다.
ILSpy에서 디버깅을 시도 했습니까? 특히 디버그 기호가 없습니다. C # 코드를 디버깅하지만 IL 명령어가 제대로 디버깅 가능한지 알려줍니다. (ILSpy 디버거는 베타 버전입니다)
원래 IL 코드에 대한 빠른 참고 사항 :
- .line 19,19 : 6,15 ”두 번 발생합니까?
- .line 20,20 : 7,14 ”는 암시 적 시퀀스 지점에서 시작되지 않습니다 (스택이 비어 있지 않음). 내가 걱정
- .line 20,20 : 7,14 ”에는 “car x”(양호)와 “#f nooo x”(나쁜?)에 대한 코드가 포함됩니다.
- ret 후 nop에 관한. Stloc, ldloc, ret은 어떻습니까? C # 은이 트릭을 사용하여 ret을 독특한 시퀀스 포인트로 만듭니다.
데이비드