먼저이 질문의 길이에 대해 사과드립니다.
나는 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를 정리하면 디버깅이 중단되지만 전환하기 쉽고 오버 헤드가 많지 않습니다.
nop
s가 없으면 스테핑이 실패합니다 (확실히 다시 확인합니다). 내가 만들어야 할 희생이다. VS는 관리자 권한 없이도 실행할 수 없습니다. : Reflection을 사용하는 Btw. DLR (매우 해킹 된 초기 분기)을 통해 방출하십시오.