Как просмотреть локальные переменные в стеке оценки при отладке приложения .NET CLR?
Вопрос
Я использую Windbg (с расширением sos) и пытаюсь отладить сбойное приложение.Мне удалось сбросить IL-код вызова, вызвавшего исключение, и, изучив код, кажется, что я мог бы получить необходимую мне информацию, если бы мог сбросить содержимое стека оценки.Можно ли что сделать с WinDbg & sos?
Вот что я сделал:
- Запустил WinDbg
- Прикреплен к аварийному процессу
- загрузка через sos mscorwks (чтобы загрузить расширение SOS)
!token2ee theModuleName 0600009а (где theModuleName Является ли название приложения (и сборки), которую я отлаживаю и 9а — это смещение метода, который произошел сбой, как сообщает инструмент отчетов об ошибках Windows..Я получил этот вывод:
Модуль:000e2c3c (ИмяПриложения.exe)
Токен:0x0600009a
Описание метода:000e67c8
Имя:MyNamespace.MyClassName.theCulpritFn(MyOtherClass)
Адрес кода JITTED:0081b1d0!дампил 00e67c8 (который сбросил IL для рассматриваемого метода).Это результат:
// .. // .. the previous code omitted for brevity .catch { IL_0071: stloc.0 IL_0072: nop IL_0073: ldstr "Can't set CurrentServer property for: " IL_0078: ldarg.0 IL_0079: ldfld MyNamespace.MyClassName::_currentServer IL_007e: brtrue.s IL_0087 IL_0080: ldstr "" IL_0085: br.s IL_0092 IL_0087: ldarg.0 IL_0088: ldfld MyNamespace.MyClassName::_currentServer IL_008d: callvirt MyNamespace.MyOtherClass::get_Name IL_0092: call System.String::Concat IL_0097: ldloc.0 IL_0098: newobj MyNamespace.MySpecialExceptionType::ctor IL_009d: throw }
Вопрос в том:Есть ли у меня способ увидеть, что было помещено в стек до того, как было выбрано исключение.Если я не ошибаюсь, аргумент, передаваемый в конструктор исключений, должен быть локальной переменной с индексом 0 в стеке вычислений.
P.S.Когда я пытался позвонить !clrstack -а Мне пришло сообщение:Невозможно пройти по управляемому стеку.Текущий поток, скорее всего, не является управляемым потоком.Вы можете запустить !threads, чтобы получить список управляемых потоков в процессе.
Спасибо!
Решение
Вам необходимо определить и выбрать нужную нить.Идентификатор текущего потока отображается в командной строке WinDbg.
!threads
отобразит все управляемые потоки в вашем приложении.После идентификации вы можете переключать потоки, используя ~Xs
где X — идентификатор WinDbg для потока.
!clrstack
покажет вам трассировку стека.Если вы хотите, чтобы локальные жители и/или параметры использовали -l
/ -p
(или -a
для обоих).
Вы можете просмотреть все потоки и перечислить их стек вызовов с помощью ~*e!clrstack
.
Если local/parameters не дает вам того, что вам нужно, используйте !dso
для отображения объектов, помещенных в стек.
Другие советы
Ух ты, как это сложно без настоящего дампа, через который можно пролезть.:-)
Вот пару вопросов..а затем я добавлю одну команду, которая ранее не была указана в ответах выше..
Вопросы:
Вы уверены, что перехватываете первое исключение, а не только последнее, которое не было обработано и прервало процесс?
Можете ли вы взглянуть на собственный стек вызовов потока, вызвавшего исключение?
Примечание:должен быть вызов RaiseException() или нарушение прав доступа.Остерегайтесь асинхронных исключений, которые не имеют абсолютно никакого отношения к вашему коду и могут попасть в блок catch...или хуже (Thread.AbortException/System.OutofMemoryException и...StackOverflowException :-)
Чтобы копнуть дальше, вы бежите !свалка в неисправной ветке..Результат: не точный однако он делает потрясающую работу по обходу стека вызовов потоков, и вам может повезти, и вы увидите @ символ, который ссылается на исключение с расширением .cxr и .exr в сообщении.Если да, то можешь бежать .cxr -cxr-адрес и посмотреть, какое исключение было первым в цепочке исключений.
Точка:Хотя я, возможно, уклоняюсь от ответа на этот вопрос, но если исключение вызвало WER, то это было не обработано и удалили процесс, который вы, возможно, захотите зарегистрировать в исходном стеке вызовов или добавить предыдущее исключение в качестве внутреннего исключения, чтобы вы могли определить основную причину.
Спасибо, Аарон