Во-первых, я прошу прощения за длину этого вопроса.
Я автор IronScheme . В последнее время я усердно работал над выдачей приличной отладочной информации, чтобы я мог использовать «нативный» отладчик .NET.
Хотя это было частично успешно, я сталкиваюсь с некоторыми проблемами при прорезывании зубов.
Первая проблема связана со степпингом.
Поскольку Scheme является языком выражений, все имеет тенденцию заключаться в круглые скобки, в отличие от основных языков .NET, которые, кажется, основаны на операторах (или строках).
Исходный код (схема) выглядит так:
(define (baz x)
(cond
[(null? x)
x]
[(pair? x)
(car x)]
[else
(assertion-violation #f "nooo" x)]))
Я специально выложил каждое выражение на новую строку.
Излучаемый код преобразуется в C # (через ILSpy) выглядит следующим образом:
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? x), за которым следует x.
- Позвоните в базу с Cons аргумент, он работает правильно. (null? x), затем (pair? x), затем (car x).
- Позвонить в базу с другим аргументом, это не удастся. (null? x) затем (pair? x) затем (car x) затем (нарушение-утверждение ...).
При применении IgnoreSymbolStoreSequencePoints
(как рекомендуется):
- Вызовите базу с нулевым аргументом, он работает правильно. (null? x), за которым следует x.
- Позвонить в базу с Cons аргумент, это не удается. (null? x) затем (pair? x).
- Позвонить в базу с другим аргументом, это не удастся. (null? x) затем (pair? x) затем (car x) затем (нарушение-утверждение ...).
Я также нахожу в этом режиме, что некоторые строки (не показаны здесь) неправильно выделены, они выключены на 1.
Вот некоторые идеи, которые могут быть причинами:
- Tailcalls смущает отладчик
- Перекрывающиеся местоположения (здесь не показаны) сбивают с толку отладчик (это очень хорошо работает при установке точки останова)
- ????
Вторая, но также серьезная проблема заключается в том, что отладчик в некоторых случаях не может сломать / достичь точки останова.
Единственное место, где я могу заставить отладчик работать корректно (и последовательно), это точка входа метода.
Ситуация становится немного лучше, когда IgnoreSymbolStoreSequencePoints
не применяется.
Вывод
Возможно, отладчик VS просто глючит :(
Ссылки:
Обновление 1:
Mdbg не работает для 64-битных сборок. Так что это вне. У меня больше нет 32-битных машин для тестирования. Обновление: я уверен, что это не большая проблема, у кого-нибудь есть исправление? Изменить: Да, глупый я, просто запустите mdbg в командной строке x64 :)
Обновление 2:
Я создал приложение на C # и попытался проанализировать информацию о линии.
Мои выводы:
- После любой
brXXX
инструкции вам нужно указать точку последовательности (если она недействительна, то есть «#line hidden», выведите anop
). - Перед любой
brXXX
инструкцией выведите «#line hidden» и anop
.
Применение этого, однако, не решает проблемы (в одиночку?).
Но добавление следующего дает желаемый результат :)
- После
ret
этого выделите «#line hidden» и anop
.
Это использует режим, где 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 нарушит отладку, но это легко переключить, и оставить их без особых накладных расходов.
nop
s, степпинг не удался (я проверю это снова, чтобы быть уверенным). Это жертва, я думаю, мне придется пойти на это. Это не то, что VS может даже работать без прав администратора :) Кстати, используя Reflection.Emit через DLR (очень взломанный ранний разветвленный).Ответы:
Я инженер в команде отладчика Visual Studio.
Поправьте меня, если я ошибаюсь, но похоже, что единственная оставшаяся проблема заключается в том, что при переключении с PDB на формат символов динамической компиляции .NET 4 пропускаются некоторые точки останова.
Нам, вероятно, потребуется репродукция, чтобы точно диагностировать проблему, однако вот некоторые замечания, которые могут помочь.
JIT создает неявную точку последовательности, основанную на следующих правилах: 1. Инструкции IL nop 2. Пустые точки стека IL 3. Инструкция IL сразу после инструкции вызова
Если выясняется, что для решения вашей проблемы нам нужно репро, вы можете сообщить об ошибке подключения и безопасно загрузить файлы через этот носитель.
Обновить:
Мы призываем других пользователей, столкнувшихся с этой проблемой, попробовать предварительную версию Dev11 для разработчиков по адресу http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27543 и оставить свои комментарии. (Должна быть цель 4.5)
Обновление 2:
Леппи проверил исправление, чтобы работать для него на бета-версии Dev11, доступной по адресу http://www.microsoft.com/visualstudio/11/en-us/downloads, как отмечено в ошибке подключения https://connect.microsoft. ru / VisualStudio / обратная связь / подробности / 684089 / .
Спасибо,
Люк
источник
VerificationException
.Я инженер в команде отладчика SharpDevelop :-)
Вы решили проблему?
Вы пытались отладить его в SharpDevelop? Если есть ошибка в .NET, мне интересно, нужно ли нам реализовать какой-то обходной путь. Я не знаю об этой проблеме.
Вы пытались отладить его в ILSpy? Особенно без отладочных символов. Это отладило бы код C #, но сообщило бы, хорошо ли отлаживаются инструкции IL. (Имейте в виду, что отладчик ILSpy бета-версия)
Быстрые заметки об оригинальном коде IL:
Дэвид
источник