Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004

.pdf
Скачиваний:
353
Добавлен:
13.08.2013
Размер:
3.3 Mб
Скачать

ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG

361

 

 

вывода будет открыт, WinDBG автоматически получает, что было записано, и вы можете начинать просматривать файл дампа.

Если вы создавали дамп на той же машине, где собирали процесс, ваша жизнь весьма проста, так как WinDBG проделает всю работу по получению символов и информации о номерах строк исходного кода. Однако большинство из нас будут анализировать файлы дампа, созданные на других машинах и других версиях ОС. После открытия файла дампа начинается работа по получению символов, настройке путей к исходному коду и исполняемым модулям.

Во!первых, определите, в каких модулях пропущена информация о символах, запустив команду LM с ключом v. Если какие!то модули сообщают «no symbols loaded» (символы не загружены), надо настроить путь для поиска символов. Посмотрите на информацию о версиях, ассоциированную с этими модулями, и соответствен! но обновите Symbol File Path (путь к файлу символов), выбрав Symbol File Path в меню File.

Второй шаг — настройка путей к файлам исполняемых образов. Как я уже го! ворил в главе 2, WinDBG нужен доступ к двоичным файлам до того, как он смо! жет загрузить символы для минидампов. Если вы следовали моим рекомендаци! ям и поместили свои программы и необходимые различным ОС двоичные фай! лы и символы в свой сервер символов, подключить двоичные файлы легко. В ди! алоговом окне Executable Image Search Path (путь к исполняемому образу), дос! тупном при выборе Image File Path (путь к файлу образа) меню File, можно про! сто вставить из буфера обмена ту же строку, что вы указали для символьного сер! вера. WinDBG автоматически найдет ваш сервер символов для соответствующих двоичных файлов.

Если двоичных файлов в хранилище символов нет, нужно указать путь вруч! ную и надеяться, что вы указали его к корректным версиям модулей. Это особен! но трудно с двоичными файлами ОС, так как очередное исправление может из! менить любое их количество. В действительности, каждый раз, внося «горячие» изменения или устанавливая пакет обновлений, вы должны перезагрузить свое хранилище символов, запустив файл OSSYMS.JS (см. главу 2).

И наконец, необходимо настроить путь к исходным текстам, выбрав Source File Path (путь к исходному файлу) из меню File. Настроив все три пути, перезагрузи! те символы командой .RELOAD /f, после которой последует команда LM, позволяю! щая увидеть все еще некорректные символы. Если минидамп доставлен от заказ! чика, вам, возможно, не удастся загрузить все двоичные файлы и символы, так как там может оказаться другой уровень внесенных исправлений или программ тре! тьих поставщиков, напихавших кучу DLL в другие процессы. Однако ваша цель — загрузить все символы ваших программ и как можно больше символов ОС. Как! никак, если вам удалось загрузить все символы, отладка становится простым делом!

Отладка дампа

Если вам удалось корректно загрузить символы и двоичные файлы, то отладка файла дампа почти идентична отладке «живьем». Очевидно, что некоторые команды, такие как BU, не будут работать с файлами дампа, но большинство других будет, особен!

362 ЧАСТЬ II Производительная отладка

но команды расширения. При возникновении проблем с командами, обратитесь к таблице окружения в документации по этой команде и проверьте, что вы може! те использовать ее при отладке файлов дампа.

Если вы имеете несколько файлов дампа сразу, вы также можете отлаживать их совместно командой .OPENDUMP (Open Dump File — открыть файл дампа). От! крыв файл дампа таким способом, необходимо дать команду G (Go — запустить), чтобы WinDBG смог все запустить.

Наконец, команда, доступная только при отладке файла дампа, — .DUMPCAB (Create Dump File CAB — создать CAB файл дампа) — создаст .CAB!файл из текущего фай! ла дампа. Если вы добавите параметр –a, все символы будут записаны в этот файл.

Son of Strike (SOS)

Имеется замечательная поддержка для отладки дампов приложений неуправляе! мого кода, но не для приложений управляемого кода, и, хотя управляемые прило! жения меньше подвержены появлению в них ошибок, отлаживать их гораздо труд! нее. Рассмотрим, например, те проекты, в которые были произведены значитель! ные вложения в COM+ или другие технологии неуправляемого кода. Вы можете и хотите создавать новые внешние интерфейсы в .NET или компоненты, усиливаю! щие ваши COM!компоненты путем использования COM interop. Когда эти прило! жения завершаются аварийно или зависают, вы тут же получаете головную боль, так как почти невозможно продраться сквозь ассемблерный код, исследовать стеки вызовов и даже найти исходные тексты и строки для этих .NET!частей прило! жения.

Чтобы помочь вам увидеть .NET!части дампа или «живого» приложения, неко! торые очень умные люди в Microsoft сделали расширение отладчика, названное SOS или Son of Strike («Дитя забастовки»). Основная документация находится в файле SOS.HTM в каталоге <Каталог установки Visual Studio .NET >\SDK\v1.1\Tool Developers Guide\Samples\SOS. Там вы определенно увидите, что «основная» — это действительно работающий термин. В сущности это список команд расширения SOS.DLL и краткие сведения об их использовании.

Если вы работаете с большими системами .NET, особенно с тяжелыми тран! закциями ASP.NET, вам также захочется загрузить 170!страничный PDF!файл «Pro! duction Debugging for .NET Framework Applications» (Отладка промышленных при! ложений для .NET Framework) с http://msdn.microsoft.com/library/default.asp?url=/ library/en!us/dnbda/html/DBGrm.asp. Если вы хотите знать, как управлять завис! шими процессами ASNET_WP.EXE, работать с потенциальными проблемами управ! ления памятью в .NET и контролировать другие экстремально!пограничные про! блемы, это прекрасный документ. Его авторы определенно отладили массу жиз! ненных систем промышленного уровня, и их знание поможет вам преодолеть многие трудности.

Вы кратко познакомитесь с командами SOS, основываясь на этих двух доку! ментах и документе сверхоткровенных трюков, но вот как начать работать с SOS внутри WinDBG, там не сказано. В этом разделе я хочу помочь вам сделать пер! вые шаги. Надеюсь, вы узнаете здесь достаточно, чтобы понимать документ «Produc! tion Debugging for .NET Framework Applications». Я не охвачу всего, например, всех

ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG

363

 

 

команд сборщика мусора, так как они рассмотрены в «Production Debugging for

.NET Framework Applications».

Прежде всего я хочу показать простой способ загрузить SOS.DLL в WinDBG. SOS.DLL является частью собственно .NET Framework, поэтому фокус в том, что! бы включить нужные каталоги в ваш путь поиска (переменная окружения PATH), чтобы WinDBG справился с загрузкой SOS.DLL. Вам надо открыть командную строку MS!DOS и выполнить VSVARS32.BAT, находящийся в каталоге <Каталог установки Visual Studio .NET >\Common7\Tools. VSVARS32.BAT настраивает вашу среду так, что все соответствующие каталоги .NET будут включены в ваш путь поиска.

После однократного исполнения VSVARS32.BAT вы получаете возможность за! грузить SOS.DLL командой .load sos из окна Command WinDBG. WinDBG всегда помещает последнее загруженное расширение на верхушку цепочки, поэтому команда !help покажет вам краткий список всех команд SOS.DLL.

Использование SOS

Возможно, лучше всего показать, как пользоваться SOS, на примере. Программа ExpectApp из набора файлов к этой книге покажет вам, как подступиться к важ! ным командам. Чтобы сохранить изложение на приемлемом уровне, я написал этот код, чтобы просто вызвать несколько методов с локальными переменными и в конце вызвать исключительную ситуацию. Я пройду через отладку примера EXCEPT! APP.EXE с помощью SOS, чтобы вы увидели, какие команды помогут узнать, где вы находитесь, когда приложение, использующее управляемый код, валится или за! висает. Так вам будет проще применять SOS для решения проблем и понимать «Production Debugging for .NET Framework Applications»

Откомпилировав EXCEPTAPP.EXE и настроив переменные среды, как я описал выше, откройте EXCEPTAPP.EXE в WinDBG и остановитесь на точке прерывания загрузчика. Чтобы заставить WinDBG остановиться, когда приложение .NET вы! зовет исключительную ситуацию, надо сообщить WinDBG о номере исключения, сгенерированного .NET. Проще всего это можно сделать, щелкнув кнопку Add в диалоговом окне Event Filters и введя в диалоговом окне Exception Filter 0xE0434F4D. Затем выберите Enabled в группе Execution и Not Handled в группе Continue. Щел! кнув OK, вы успешно настроите WinDBG так, чтобы он останавливался каждый раз, когда вырабатывается исключение .NET. Если значение 0xE0434F4D кажется чем!то знакомым, узнать, что это такое, поможет команда .formats.

Настроив исключения, запустите EXCEPTAPP.EXE, пока она не остановится на исключении .NET. WinDBG сообщит о нем, как о первом исключении, и остано! вит приложение на реальном вызове Win32 API RaiseException. Загрузив SOS ко! мандой .load sos, выполните !threads (ее вы всегда будете хотеть исполнять пер! вой в SOS) и вы увидите, какие потоки в приложении или дампе имеют код .NET. В случае EXCEPTAPP.EXE команда потоков WinDBG ~ указывает, что в приложении исполняются три команды. Однако команда всеобщей важности !threads показы! вает, что только потоки 0 и 2 имеют некоторый код .NET (чтобы все поместилось на странице, я привожу информацию индивидуальных потоков в виде таблицы, в WinDBG вы видите это как длинные горизонтальные строки):

364 ЧАСТЬ II Производительная отладка

0:000> !threads

PDB symbol for mscorwks.dll not loaded succeeded

Loaded Son of Strike data table version 5 from "e:\WINNT\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll" ThreadCount: 2

UnstartedThread: 0

BackgroundThread: 1

PendingThread: 0

DeadThread: 0

Row Heading

WinDBG Thread ID 0 2

Win32 Thread ID 884 9dc

ThreadObj 00147c60 001631c8

State 20 1220

PreEmptive GCEnabled Enabled

GC Alloc Context 04a45f24:04a45ff4 00000000:00000000

Domain 00158300 00158300

Lock Count 0 0

APT Ukn Ukn

Exception System.ArgumentException (Finalizer)

Важная информация в отображении команды !threads содержит поле Domain (домен), говорящее о том, много ли доменов приложения (AppDomain) исполня! ется в рамках процесса, и поле Exceptions, которое оказывается перегруженным. В примере EXCEPTAPP.EXE первый поток вызвал System.ArgumentException, поэтому вы можете видеть текущее исключение для любого потока. Третий поток EXCEPT! APP.EXE показывает специальное значение (Finalizer), обозначающее, как вы можете полагать, завершающий поток процесса. Вы также увидите (Theadpool Worker), (Threadpool Completion Port) или (GC) в поле Exception. Когда вы видите одно из этих специальных значений, знайте, что они представляют потоки времени исполне! ния, а не ваши потоки.

Так как мы определили, что поток WinDBG 0 содержит исключение EXCEPT! APP.EXE, вы захотите взглянуть на стек вызовов с помощью !clrstack –all, чтобы увидеть все детали стека, включая параметры и локальные переменные. Хотя !clrstack имеет ключи для просмотра локальных переменных ( l) и параметров ( p), не указывайте их вместе, иначе они аннулируют друг друга. Чтобы увидеть весь стек вызовов сразу, дайте команду ~*e !clrstack.

** Имейте в виду, что я вырезал отсюда регистры ** 0:000> !clrstack –all

Thread 0

ESP EIP

0012f5e0 77e73887 [FRAME: HelperMethodFrame]

0012f60c 06d3025f [DEFAULT] [hasThis] Void ExceptApp.DoSomething.Doh (String,ValueClass ExceptApp.Days)

ГЛАВА 8

Улучшенные приемы для неуправляемого кода с использованием WinDBG

365

 

 

at [+0x67] [+0x16] c:\junk\cruft\exceptapp\class1.cs:14

 

PARAM: this: 0x04a41b5c (ExceptApp.DoSomething)

 

PARAM: value class ExceptApp.Days StrParam

 

PARAM: unsigned int8 ValueParam: 0x07

 

0012f630

06d301e2 [DEFAULT] [hasThis] Void ExceptApp.DoSomething.Reh

 

(I4,String) at [+0x6a] [+0x2b] c:\junk\cruft\exceptapp\class1.cs:23

PARAM: this: 0x04a41b5c (ExceptApp.DoSomething)

PARAM: class System.String i: 0x00000042

PARAM: int8 StrParam: 77863812

LOCAL: class System.String s: 0x04a45670 (System.String)

LOCAL: value class ExceptApp.Days e: 0x003e5278 0x0012f63c

Похоже, в отображении параметров есть ошибка, так как команда !clrstack не всегда корректно отображает тип параметра. В методе DoSomething.Doh вы можете увидеть, что он принимает значения String (StrParam) и Days (ValueParam). Однако информация PARAM: показывает параметр StrParam как value class ExceptApp.Days и ValueParam как unsigned int8. К счастью для параметров размерного типа, даже ког! да тип их неверен, рядом с именем параметра отображается его корректное зна! чение. В примере с ValueParam переданное значение 7 соответствует перечисле! нию Fri.

Прежде чем перейти к постижению значений размерных классов и объектов, я хочу отметить одну команду просмотра стека, которую, возможно, вы найдете полезной. Если вы работаете над сложными вызовами между .NET и неуправляе! мым кодом, вам понадобится увидеть стек вызовов, включающий все, и в этом случае команда !dumpstack — ваш лучший друг. В целом она делает отличную работу, но, имея полную PDB!базу символов для .NET Framework, она могла бы делать ее луч! ше. Временами !dumpstack сообщает «Use alternate method which may not work» (воспользуйтесь альтернативным методом, так как этот может не работать), что, кажется, указывает на то, что производится попытка просмотреть стек при отсут! ствии информации о некоторых символах.

Строки LOCAL: показывают, что в DoSomething.Reh имеются две локальных пере! менных: s (объект String) и e (размерный класс Days). После каждого выводится шестнадцатеричный адрес, описывающий тип. Для размерного класса Days име! ются два числа 0x003E5278 и 0x0012F63C. Первое — таблица методов, второе — рас! положение значения в памяти. Чтобы увидеть это значение в памяти, просто дай! те команду распечатки содержимого памяти WinDBG, такую как dd 0x0012F63C.

Просмотр таблицы методов, описывающей данные метода, информацию о модуле и карту интерфейса среди всего прочего осуществляется командой SOS !dumpmt. Выполнение !dumpmt 0x003E5278 для примера EXCEPTAPP.EXE выводит:

0:000> !dumpmt 0x003e5278 EEClass : 06c03b1c

Module : 001521a0

Name: ExceptApp.Days

mdToken: 02000002 (D:\Dev\ExceptApp\bin\Debug\ExceptApp.exe) MethodTable Flags : 80000

Number of IFaces in IFaceMap : 3

366 ЧАСТЬ II Производительная отладка

Interface Map : 003e5380

Slots in VTable : 55

В таблице методов, отображаемой двумя первыми числами, видно, в каком модуле определен этот метод, а также класс исполняющей системы .NET. Для ин! терфейсов в документации SOS есть прекрасный пример, как пройтись по кар! там интерфейсов, и я бы одобрил ваше знакомство с ним. Если у вас есть горячее желание увидеть все методы в виртуальной таблице конкретного класса или объекта вместе с описателями методов, можно задать ключ md в команде перед значением таблицы методов. В случае EXCEPTAPP.EXE и ее размерного класса ExceptApp.Days, будут перечислены 55 методов. Как указывает документация SOS в разделе «How Do I… ?», просмотр дескрипторов методов полезен при установке точек прерыва! ния на конкретных методах.

Так как мы рассматриваем информацию класса и модуля для таблицы методов ExceptApp.Days, я сделаю небольшое отступление. Как только вы получите адрес класса исполняющей системы .NET, !dumpclass покажет вам все, что вы только могли по! желать узнать о классе, в том числе и информацию обо всех полях данных клас! са. Чтобы увидеть информацию о модуле, дайте команду !dumpmodule. В докумен! тации есть пример, как с помощью вывода !dumpmodule пройтись по памяти и най! ти классы и таблицы методов модуля.

Теперь, когда у нас есть основы размерного класса, взглянем осмысленно на локальную переменную s класса String в DoSomething.Reh:

LOCAL: class System.String s: 0x04a45670 (System.String)

Так как s — объект, то после имени переменной отображается только одно шестнадцатеричное значение — размещение объекта в памяти. С помощью команды !dumpobj вы увидите всю информацию об объекте:

0:000> !dumpobj 0x04a45670

 

 

 

 

Name: System.String

 

 

 

 

 

MethodTable 0x79b7daf0

 

 

 

 

EEClass 0x79b7de3c

 

 

 

 

 

Size 92(0x5c) bytes

 

 

 

 

 

mdToken: 0200000f

(e:\winnt\microsoft.net\framework\v1.1.4322\mscorlib.dll)

String: Tommy can you see me? Can you see me?

 

 

FieldDesc*: 79b7dea0

 

 

 

 

MT

Field

Offset

Type

Attr

Value

Name

79b7daf0

4000013

4

System.Int32

instance

38

_arrayLength

79b7daf0

4000014

8

System.Int32

instance

37

m_stringLength

79b7daf0

4000015

c

System.Char

instance

54

m_firstChar

79b7daf0

4000016

0

CLASS

shared

static

Empty

>> Domain:Value 00158298:04a412f8 <<

 

 

 

79b7daf0

4000017

4

CLASS

shared

static

WhitespaceChars

>> Domain:Value 00158298:04a4130c <<

 

 

 

Значения некоторых полей MethodTable, EEClass и MT (или Method Table) мо! гут использоваться в командах, которые мы только что обсудили. Что касается членов полей, то !dumpobj для простых размерных типов показывает их значения прямо в таблице. Для объекта класса String из предыдущего примера значение

ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG

367

 

 

m_stringLength, равное 37, показывает количество символов в строке. Как вы сей! час увидите в полях членов объекта поле Value содержит экземпляр объекта, а вы можете дать команду !dumpobj, чтобы увидеть это значение.

Строки, ограниченные знаками >> и << показывают экземпляр домена и поло! жение в домене статического поля перед знаком >>. Если бы в EXCEPTAPP.EXE содержалось несколько доменов приложения, вы бы увидели сведения о двух до! менах и значениях для статического поля WhitespaceChars.

Теперь, когда я осветил некоторые основные команды, я хочу связать их вме! сте и показать, как с их помощью искать полезную информацию. Так как программа EXCEPTAPP.EXE остановлена WinDBG в результате возникшего исключения, было бы хорошо увидеть, какая исключительная ситуация возникла и что содержат некоторые поля, в результате чего можно было бы узнать, почему EXCEPTAPP.EXE остановилась.

Из команды !threads мы знаем, что первый поток в настоящее время исполня! ет исключительную ситуацию System.ArgumentException. Приглядевшись к выводу команд !clrstack или !dumpstack, вы заметите, что нет никаких локальных пере! менных или параметров, для которых был бы указан тип System.ArgumentException. Хорошие новости в том, что хорошая команда показывает все объекты, находя! щиеся в настоящее время в стеке текущего потока:

0:000> !dumpstackobjects

 

ESP/REG

Object

Name

 

ebx

04a45670

System.String

Tommy can you see me? Can you see me?

0012f50c

04a45f64

System.ArgumentException

0012f524

04a45f64

System.ArgumentException

0012f538

04a45f64

System.ArgumentException

0012f558

04a44bc4

System.String

Reh =

0012f55c

04a45f64

System.ArgumentException

0012f560

04a45670

System.String

Tommy can you see me? Can you see me?

0012f564

04a4431c

System.Byte[]

 

0012f568

04a43a58

System.IO.__ConsoleStream

0012f5a0

04a45f64

System.ArgumentException

 

 

 

 

Так как !dumpstackobjects бродит по стеку вверх, вы увидите некоторые элементы много раз, так как они передаются как параметры ко многим функциям. В преды! дущей распечатке вы могли увидеть несколько объектов System.ArgumentException, но, посмотрев на значение объекта рядом с каждым объектом, вы заметите, что все они ссылаются на один и тот же экземпляр объекта 0x04A45F64.

Чтобы увидеть объект System.ArgumentException я использую команду !dumpobj. Я перенес колонку Name на следующую строку, чтобы все поместилось на одной странице.

0:000> !dumpobj 04a45f64

Name: System.ArgumentException

MethodTable 0x79b87b84

EEClass 0x79b87c0c

Size 68(0x44) bytes

mdToken: 02000038 (e:\winnt\microsoft.net\framework\v1.1.4322\mscorlib.dll)

368

ЧАСТЬ II

Производительная отладка

 

 

 

 

 

 

 

 

FieldDesc*: 79b87c70

 

 

 

 

 

MT

Field

Offset

Type

Attr

Value

Name

79b7fcd4

400001d

4

CLASS

instance

00000000

_className

79b7fcd4

400001e

8

CLASS

instance

00000000

 

 

 

 

 

 

_exceptionMethod

79b7fcd4

400001f

c

CLASS

instance

00000000

 

 

 

 

 

 

_exceptionMethodString

79b7fcd4

4000020

10

CLASS

instance

04a456cc

_message

79b7fcd4

4000021

14

CLASS

instance

00000000

 

 

 

 

 

 

 

_innerException

79b7fcd4

4000022

18

CLASS

instance

00000000

_helpURL

79b7fcd4

4000023

1c

CLASS

instance

00000000

_stackTrace

79b7fcd4

4000024

20

CLASS

instance

00000000

 

 

 

 

 

 

_stackTraceString

79b7fcd4

4000025

24

CLASS

instance

00000000

 

 

 

 

 

 

_remoteStackTraceString

79b7fcd4

4000026

2c

System.Int32

instance

0

 

 

 

 

 

 

_remoteStackIndex

79b7fcd4

4000027

30

System.Int32

instance

2147024809 _HResult

79b7fcd4

4000028

28

CLASS

instance

00000000

_source

79b7fcd4

4000029

34

System.Int32

instance

0

_xptrs

79b7fcd4

400002a

38

System.Int32

instance

532459699 _xcode

79b87b84

40000d7

3c

CLASS

instance

04a45708

m_paramName

Важным свойством в исключении является Message. Так как я не могу вызвать метод прямо из WinDBG, чтобы увидеть это значение, я взгляну на поле _message, так как это и есть то место, где свойство Message хранит реальную строку. Так как поле _message помечено как CLASS, то шестнадцатеричное число в столбце Value является экземпляром объекта. Чтобы увидеть этот объект, я выполню еще одну команду !dumpobj, чтобы просмотреть его. Как мы видим, объект String имеет спе! циальное поле, поэтому мы можем видеть его действительное значение, которое выворачивается в безобидное «Thowing an exception».

0:000> !dumpobj 04a456cc

 

 

 

 

Name: System.String

 

 

 

 

 

MethodTable 0x79b7daf0

 

 

 

 

EEClass 0x79b7de3c

 

 

 

 

 

Size 60(0x3c) bytes

 

 

 

 

 

mdToken: 0200000f

(e:\winnt\microsoft.net\framework\v1.1.4322\mscorlib.dll)

String: Thowing an exception

 

 

 

FieldDesc*: 79b7dea0

 

 

 

 

MT

Field

Offset

Type

Attr

Value

Name

79b7daf0

4000013

4

System.Int32

instance

21

m_arrayLength

79b7daf0

4000014

8

System.Int32

instance

20

m_stringLength

79b7daf0

4000015

c

System.Char

instance

54

m_firstChar

79b7daf0

4000016

0

CLASS

shared

static

Empty

>> Domain:Value 00158298:04a412f8 <<

 

 

 

79b7daf0

4000017

4

CLASS

shared

static

WhitespaceChars

>> Domain:Value 00158298:04a4130c <<

 

 

 

ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG

369

 

 

Резюме

Моя цель была показать мощь WinDBG и помочь вам преодолеть препятствия, которые вы встретите на своем пути. Если я еще недостаточно говорил об этом, позвольте повторить, что вам действительно необходимо читать документацию WinDBG.

Самый большой фокус в WinDBG — настройка символов и пути к исходным текстам, а также при отладке дампа, настройка пути к образу исполняемого фай! ла. WinDBG потрясающе гибок, позволяя управлять поиском символов и источ! ника их загрузки.

В дополнение к возможности отлаживать несколько процессов одновремен! но WinDBG предлагает средства управления точками прерывания, так что вы можете остановиться точно там и тогда, где и когда пожелаете. Способность исполнять команды как в точках прерывания, так и в исключительных ситуациях, дает ис! ключительную возможность отслеживать самые трудные ошибки. Команды рас! ширения помогают увидеть внутри процессов то, что невозможно было видеть раньше.

Одна из самых важных причин применения WinDBG — управление дампами. Хотя Visual Studio .NET предлагает читать файлы дампов, но это применимо толь! ко для дампов, созданных на машинах разработчиков. WinDBG — инструмент, позволяющий читать реальные файлы дампов, полученных от заказчиков.

Наконец, я надеюсь, что смог предоставить вам стартовые позиции для исполь! зования интереснейшей библиотеки расширения SOS, поддерживающей отладку

.NET. Как ни крути, это единственный способ отладить приложения, в которых скомбинированы управляемый и неуправляемый код. Вам, конечно, понадобится время на то, чтобы полностью освоить SOS. Кроме того, чтение «Production Debug! ging for .NET Framework Applications» необходимо для понимания трудностей, которые таят огромные сверхмощные приложения.

Ч А С Т Ь I I I

МОЩНЫЕ СРЕДСТВА И МЕТОДЫ ОТЛАДКИ ПРИЛОЖЕНИЙ .NET

Соседние файлы в предмете Программирование на C++