Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004
.pdfГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG |
331 |
|
|
выглядит несколько иначе. Я опишу справочную систему по этим командам в раз деле «Магические расширения». И еще: стандартные и мета команды не чувстви тельны к регистру, но все команды расширения вводятся в нижнем регистре.
Возможно, мета команда .hh (Open HTML Help File — открыть HTML файл спра вочной системы) самая важная. Указание имени команды в качестве параметра .hh откроет файл справочной системы DEBUGGER.CHM на вкладке Index (указатель), где указанная команда будет подсвечена. Просто нажмите Enter, и появится спра вочная информация по этой команде. Надеюсь, в будущих версиях разработчики WinDBG исправят команду .hh так, чтобы она автоматически открывала раздел справочной системы, относящийся к заданной команде.
При ознакомлении со справочной системой по командам обратите особое внимание на раздел Environment (среда), появляющийся в каждой команде. Таб лица этого раздела описывает ситуации, в которых WinDBG может исполнить команду. Очевидно, что при отладке пользовательского режима, поле Modes (ре жимы) должно будет распознать пользовательский режим. Почти все команды пользовательского режима работают как при выполнении живой отладки, так и при работе с минидампами.
Единственное, что еще не очень ясно в справочной системе для всех команд, — это почему полностью отсутствует логика, когда вы переходите к параметрам, передаваемым командам. Одни команды принимают параметры, которые долж ны отделяться символом «минус», другие требуют слэша, а третьи вообще не име ют разделителей. Отнеситесь внимательно к документации, чтобы правильно ука зывать параметры для каждой команды.
Обеспечение корректной загрузки символов
WinDBG превосходен в обработке символов. В то время как Visual Studio .NET не предоставляет вам ни единого шанса увидеть, что же все таки загружено, WinDBG показывает все. Отлаживая неуправляемый код, я использую WinDBG, чтобы быть уверенным, что все мои символы настроены, прежде чем перейти к Visual Studio
.NET. В итоге я точно знаю, где нахожусь, что не хожу по комментариям и что нет символов ОС, указывающих никуда.
Важнейшая возможность обработки символов в WinDBG в том, что в любой момент можно заставить его перезагрузить все символы. В нижней части окна Symbol Search Path (путь поиска символов) есть флажок Reload (перезагрузить). Изменив каталог символов, установите его и щелкните кнопку OK, и WinDBG выгрузит все загруженные символы и загрузит их вновь, исходя из нового ката лога символов. Это позволяет выбрать наилучшие символы из возможных. Есть и команды для перезагрузки символов, но сначала я должен показать, как удостове риться, какие символы вы загрузили.
Когда окно Command активно, команда LM (List Loaded Modules — список за груженных модулей) покажет список модулей и соответствующие им файлы сим волов. В качестве примера я загрузил программу ASSERTTEST.EXE, которая помо гает проверить SUPERASSERT (имеется в файлах примеров к этой книге), в WinDBG. Если WinDBG остановить на точке прерывания загрузчика, запуск LM покажет:
332 |
ЧАСТЬ II |
Производительная отладка |
|
|
|
|
|
0:000> lm |
|
|
|
start |
end |
module name |
|
00400000 |
0040a000 |
AssertTest |
(deferred) |
10200000 |
10287000 |
MSVCR71D |
(deferred) |
10480000 |
1053c000 |
MSVCP71D |
(deferred) |
60000000 |
6004a000 |
BugslayerUtil (deferred) |
|
6d510000 |
6d58d000 |
dbghelp |
(deferred) |
70a70000 |
70ad4000 |
SHLWAPI |
(deferred) |
71950000 |
71a34000 |
COMCTL32 |
(deferred) |
77c00000 |
77c07000 |
VERSION |
(deferred) |
77c10000 |
77c63000 |
msvcrt |
(deferred) |
77c70000 |
77cb0000 |
GDI32 |
(deferred) |
77d40000 |
77dc6000 |
USER32 |
(deferred) |
77dd0000 |
77e5d000 |
ADVAPI32 |
(deferred) |
77e60000 |
77f46000 |
kernel32 |
(deferred) |
77f50000 |
77ff7000 |
ntdll |
(pdb symbols) |
|
|
\\zeno\WebSymbols\ntdll.pdb\3D6DE29B2\ntdll.pdb |
|
78000000 |
78086000 |
RPCRT4 |
(deferred) |
Так как загрузка символов занимает огромный объем памяти, WinDBG исполь зует отложенную загрузку символов, т. е. загружает символы, только когда они нужны. Поскольку исходное предназначение WinDBG — отлаживать ОС, загрузка всех символов ОС при первом присоединении к ядру системы сделает WinDBG бесполезным. Таким образом, только что приведенный пример показывает, что я загрузил только символы NTDLL.DLL. Остальные помечены как «deferred» (отло жены), потому что у WinDBG нет причин получать доступ к ним. Если б я загру зил файл исходного текста ASSERTTEST.EXE и нажал F9 для установки точки пре рывания на строке, WinDBG начал бы загрузку этих символов, пока не нашел бы нужный в этом файле. Вот зачем нужно информационное окно с запросом необ ходимости загрузки символов. Однако на уровне командной строки вы можете бо лее тонко управлять выбором загружаемых символов.
Чтобы заставить загрузить символ, команда LD (Load Symbols — загрузить сим волы) делает небольшой трюк. LD принимает только имя файла в командной строке, поэтому, чтобы загрузить символы программы ASSERTTEST.EXE, я ввел ld asserttest и получил такой результат:
0:000> ld asserttest
*** WARNING: Unable to verify checksum for AssertTest.exe
Symbols loaded for AssertTest
WinDBG весьма обстоятелен при работе с символами и сообщает о символах все, что может быть потенциально ошибочным. Так как я использую отладочную версию ASSERTTEST.EXE, то у меня не был задан ключ /RELEASE при сборке про граммы, отключающий инкрементальную компоновку. Как я говорил в главе 2, ключ /RELEASE называется неправильно, он должен бы называться /CHECKSUM, так как он лишь добавляет контрольную сумму к двоичному файлу и PDB файлу.
Чтобы загрузить все символы, укажите символ «звездочка» как параметр команды LD: ld *. Порывшись в документации WinDBG, вы увидите другую команду — RELOAD (Reload Module — перезагрузить модуль), которая в сущности делает то же, что и LD. Для загрузки всех символов с помощью .RELOAD, задайте параметр /f: .RELOAD /f.
ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG |
333 |
|
|
Если вы отлаживаете большую программу, .RELOAD может оказаться немного по лезнее, так как она будет сообщать только о тех модулях, у которых имеются про блемы с символами, тогда как LD покажет результат загрузки каждого модуля. В любом случае вы сразу узнаете, какие символы некорректны.
Вы также можете проверить правильность загрузки символов командой LM. После загрузки всех символов LM выводит следующее (я перенес последний элемент каждой строки на следующую строку, чтобы все поместилось по ширине на странице):
0:000> lm |
|
|
|
|
start |
end |
module name |
|
|
00400000 |
0040a000 |
AssertTest |
C (pdb symbols) |
|
|
|
D:\Dev\BookTwo\Disk\Output\AssertTest.pdb |
||
10200000 |
10287000 |
MSVCR71D |
(pdb |
symbols) |
|
|
e:\winnt\system32\msvcr71d.pdb |
||
10480000 |
1053c000 |
MSVCP71D |
(pdb |
symbols) |
|
|
e:\winnt\system32\msvcp71d.pdb |
||
60000000 |
6004a000 |
BugslayerUtil |
C |
(pdb symbols) |
|
|
D:\Dev\BookTwo\Disk\Output\BugslayerUtil.pdb |
||
6d510000 |
6d58d000 |
dbghelp |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\dbghelp.pdb\ |
||
|
|
819C4FBAB64844F3B86D0AEEDDCE632A1\dbghelp.pdb |
||
70a70000 |
70ad4000 |
SHLWAPI |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\shlwapi.pdb\3D6DE26F2\shlwapi.pdb |
||
71950000 |
71a34000 |
COMCTL32 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\MicrosoftWindowsCommon Controls |
||
|
|
60100 comctl32.pdb\3D6DD9A81\ |
||
|
|
MicrosoftWindowsCommon Controls |
||
|
|
60100 comctl32.pdb |
|
|
77c00000 |
77c07000 |
VERSION |
(pdb |
symbols) |
|
|
e:\winnt\symbols\dll\version.pdb |
||
77c10000 |
77c63000 |
msvcrt |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\msvcrt.pdb\3D6DD5921\msvcrt.pdb |
||
77c70000 |
77cb0000 |
GDI32 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\gdi32.pdb\3D6DE59F2\gdi32.pdb |
||
77d40000 |
77dc6000 |
USER32 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\user32.pdb\3DB6D4ED1\user32.pdb |
||
77dd0000 |
77e5d000 |
ADVAPI32 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\advapi32.pdb\3D6DE4CE2\advapi32.pdb |
||
77e60000 |
77f46000 |
kernel32 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\kernel32.pdb\3D6DE6162\kernel32.pdb |
||
77f50000 |
77ff7000 |
ntdll |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\ntdll.pdb\3D6DE29B2\ntdll.pdb |
||
78000000 |
78086000 |
RPCRT4 |
(pdb |
symbols) |
|
|
\\zeno\WebSymbols\rpcrt4.pdb\3D6DE2F92\rpcrt4.pdb |
||
Буква «C» после имени модуля указывает, что в модуле или файле символов отсутствует контрольная сумма символов. Символ «решетка» после имени модуля указывает, что символы в файле символов и исполняемом файле не соответству ют друг другу. Да, WinDBG загрузит символы посвежее, даже если это неправиль но. В предыдущем примере жизнь хороша, и все символы коррректны. Однако со
334 ЧАСТЬ II Производительная отладка
вершенно нормально, что «решетка» стоит рядом с COMCTL32.DLL. Это потому, что он, видимо, меняется с каждым пакетом обновления, исправляющим ошибку защиты в Microsoft Internet Explorer, и шансы получить в распоряжение коррект ную таблицу символов для COMCTL32.DLL почти нулевые. Чтобы поточнее узнать, какие модули и соответствующие файлы символов загружены, укажите v в коман де LM. Чтобы показать единственный модуль в следующем примере, я задал пара метр m для выбора конкретного модуля.
(pdb symbols) \\zeno\WebSymbols\ gdi32.pdb\3D6DE59F2\gdi32.pdb
Loaded symbol image file: E:\WINNT\system32\GDI32.dll
Image path: E:\WINNT\system32\GDI32.dll
Timestamp: Thu Aug 29 06:40:39 2002 (3D6DFA27) Checksum: 0004285C
File version: |
5.1.2600.1106 |
Product version: |
5.1.2600.1106 |
File flags: |
0 (Mask 3F) |
File OS: |
40004 NT Win32 |
File type: |
2.0 Dll |
File date: |
00000000.00000000 |
CompanyName: |
Microsoft Corporation |
ProductName: |
Microsoft® Windows® Operating System |
InternalName: |
gdi32 |
OriginalFilename: |
gdi32 |
ProductVersion: |
5.1.2600.1106 |
FileVersion: |
5.1.2600.1106 (xpsp1.020828 1920) |
FileDescription: |
GDI Client DLL |
LegalCopyright: |
© Microsoft Corporation. All rights reserved. |
Чтобы точно узнать, где WinDBG загружает символы и почему, расширенная команда !sym предлагает параметр noisy. Вывод в окнах Command показывает, через что проходит сервер символов WinDBG, чтобы найти и загрузить символы. Во оружившись этими результатами, вы сможете решить всевозможные проблемы за грузки символов, с которыми столкнетесь. Чтобы отключить многословный вы вод, исполните команду !sym quiet.
И последнее о символах. WinDBG имеет встроенный браузер символов. Коман да X (Examine Symbols — проверить символы) позволяет просматривать символы глобально, применительно к модулю или в локальном контексте. Указав формат module!symbol, вы избавите себя от выслеживания места хранения символа. Кроме того, команда X не чувствительна к регистру, что упрощает жизнь. Чтобы увидеть адрес символа LoadLibraryW в памяти, введите:
0:000> x kernel32!LoadLibraryw
77e8a379 KERNEL32!LoadLibraryW
Формат module!symbol поддерживает «звездочку», поэтому, если вы хотите, на пример, увидеть в модуле KERNEL32.DLL что либо, имеющее «lib» в имени симво
ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG |
335 |
|
|
ла, введите x kernel32!*Lib*, что хорошо работает и тоже не чувствительно к ре гистру. Чтобы увидеть все символы модуля, напишите «звездочку» вместо имени символа. Использование «звездочки» в качестве параметра приведет к выводу ло кальных переменных в текущей области видимости, что идентично команде DV (Display Variables — отобразить переменные), которую мы обсудим в разделе «Про смотр и вычисление переменных».
Процессы и потоки
Разобравшись с символами, можно перейти к запуску процессов под управлени ем WinDBG. Подобно Visual Studio .NET, WinDBG способен отлаживать одновре менно любое количество процессов. Немного интереснее его делает то, что вы располагаете лучшим контролем над отлаживаемыми процессами, порожденны ми из отлаживаемого процесса.
Отладка дочерних процессов
В самом низу диалогового окна Open Executable (рис. 8 2) имеется флажок Debug Child Processes Also (отлаживать также и дочерний процесс). Установив его, вы сообщаете WinDBG, что вы также хотите отлаживать любые процессы, запущен ные отлаживаемым процессом. При работе под Microsoft Windows XP/Server 2003, если вы забыли установить этот флажок при открытии процесса, вы можете из менить этот параметр «на лету» командой .CHILDDBG (Debug Child Processes — от лаживать дочерний процесс). Собственно .CHILDDBG сообщит вам текущее состоя ние. Команда .CHILDDBG 1 включит отладку дочерних процессов, а .CHILDDBG 0 от ключает ее.
Чтобы показать возможности работы со многими процессами и потоками, я приведу несколько результирующих распечаток отладки процессора командной строки (CMD.EXE). После того как CMD.EXE начнет исполняться, я запущу NOTE PAD.EXE. Если вы проделаете те же шаги при разрешенной отладке дочерних про цессов, как только загрузите NOTEPAD.EXE, WinDBG остановится на точке преры вания загрузчика для NOTEPAD.EXE. То, что WinDBG остановил NOTEPAD.EXE, — логично, но это останавливает и CMD.EXE, так как оба процесса теперь работают совместно в одном цикле отладки.
Чтобы увидеть в графическом интерфейсе исполняющиеся сейчас процессы, выберите Processes And Threads (процессы и потоки) из меню View. Вы увидите нечто вроде того, что изображено на рис. 8 3. В окне Processes And Threads про цессы изображены как корневые узлы, а потоки процессов — как дочерние. Чис ла рядом с CMD.EXE (000:9AC) являются номером процесса WinDBG, после кото рого указан идентификатор процесса Win32. Для CMD.EXE поток 000:9B0 обозна чает идентификатор потока WinDBG и идентификатор потока Win32. Номера процессов и потоков WinDBG уникальны в течение всего времени работы WinDBG. Это значит, что никогда не может появиться другой процесс с номером 1, пока я не перезапущу WinDBG. Номера процессов и потоков WinDBG важны, так как они служат для установки точек прерывания для процессов и потоков, а также могут использоваться в качестве модификаторов в командах.
336 ЧАСТЬ II Производительная отладка
Рис. 8 3. Окно Processes And Threads
Просмотр процессов и потоков в окне Command
Все, что WinDBG отображает в окне, позволяет просмотреть соответствующая команда окна Command. Для просмотра процессов и потоков служит команда | (Process Status — состояние процесса). Результат работы для двух процессов, по казанных на рис. 8 3, выглядит так:
1:001> | |
|
|
|
0 |
id: 9ac |
create |
name: cmd.exe |
. 1 |
id: 3d0 |
child |
name: notepad.exe |
Точка в левой позиции индицирует активный процесс, т. е. все вводимые вами команды будут работать с этим процессом. Другое интересное поле показывает, как был запущен процесс в отладчике. «Create» означает, что процесс создан Win DBG, а «child» — процесс, порожденный родительским процессом.
Перегруженная команда S имеет два варианта: |S (Set Current Process — уста новить текущий процесс), а ~S (Set Current Thread — установить текущий поток) изменяет текущий активный процесс. К вашим услугам также окно Processes And Threads (процессы и потоки), вызываемое двойным щелчком процесса, который вы хотите сделать активным. Полужирным начертанием выделен активный про цесс. Используя команду S, необходимо задать процесс в виде префикса коман ды. Так, для переключения со второго процесса на первый, нужно ввести |0s. Чтобы выяснить, какой процесс активен, взгляните на крайние слева номера строки ввода окна Command. При смене процессов номера меняются. В примере с CMD.EXE и NOTEPAD.EXE при переключении на первый процесс путем повторной выдачи команды | результат выглядит немного иначе:
0:000> | |
|
|
|
|
. |
0 |
id: 9ac |
create |
name: cmd.exe |
# |
1 |
id: 3d0 |
child |
name: notepad.exe |
ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG |
337 |
|
|
Разница — в символе «#» перед процессом NOTEPAD.EXE. Символ «#» указывает процесс, вызвавший исключение, остановившее его в WinDBG. Так как NOTEPAD.EXE находится на точке прерывания, то последняя и является причиной исключения.
Просмотр потоков почти идентичен просмотру процессов. Я собираюсь запу стить NOTEPAD.EXE, поэтому я в WinDBG нажимаю F5. В NOTEPAD.EXE я открою диалоговое окно File Open (открыть файл), так как оно создаст целый букет по токов, а в WinDBG нажму Ctrl+Break для прерывания внутри отладчика. Если вы проделываете то же самое и у вас открыто окно Processes And Threads, вы увиди те, что NOTEPAD.EXE имеет четыре потока, а CMD.EXE — два.
Команда ~ (Thread Status — состояние потока) показывает активные потоки текущего процесса. Переключение к процессу NOTEPAD.EXE и ввод команды ~ выводит следующую информацию:
1:001> ~ |
|
|
|
. 1 |
Id: 3d0.39c Suspend: 1 Teb: 7ffde000 Unfrozen |
||
2 |
Id: 3d0.1a4 Suspend: 1 |
Teb: 7ffdd000 Unfrozen |
|
3 |
Id: 3d0.8f0 Suspend: 1 |
Teb: 7ffdc000 |
Unfrozen |
4 |
Id: 3d0.950 Suspend: 1 |
Teb: 7ffdb000 |
Unfrozen |
Как и в случае с |, команда ~ использует точку для индикации текущего пото ка, а символ «#» — для обозначения потока, который либо вызвал исключение, либо был активен при подключении к нему отладчика. В следующем столбце отобра жается номер потока WinDBG. Так же, как и с номерами процессов, может быть только один поток с номером 2 за все время жизни экземпляра WinDBG. Далее идут значения ID — идентификаторы процессов Win32, за которыми следуют иден тификаторы потоков. Счетчик приостановок (suspend count) немного сбивает с толку. Значение счетчика 1 указывает на то, что поток не приостанавливался. Спра вочная система по команде ~ показывает значение счетчика приостановок, рав ное 0, которого я никогда не видел. После счетчика приостановок идет линейный адрес (linear address) блока переменных окружения потока (Thread Environment Block, TEB). TEB — это то же, что и блок информации о потоке (Thread Information Block, TIB), обсуждавшийся в главе 7, который в свою очередь является адресом блока данных потока, содержащего информацию экземпляра потока, такую как стек и параметры инициализации COM. Наконец, Unfrozen (размороженный) ин дицирует, использовали ли вы команду ~F (Freeze Thread — заморозить поток) для «замораживания» потока. Замораживание потока в отладчике сродни вызову Suspend Thread для этого потока из вашей программы. Это остановит поток до его «размо розки».
По умолчанию команда работает для текущего потока, но иногда хочется уви деть информацию и о другом потоке. Скажем, чтобы увидеть регистры другого потока, надо использовать модификатор потока перед командой R (Registers — ре гистры): ~2r. Если у вас открыто несколько процессов, нужно также добавлять к командам модификатор процесса. Команда |0~0r показывает регистры для первого процесса и первого потока независимо от того, какие процесс и поток активны.
Создание процессов из окна Command
Теперь, когда вы научились просматривать процессы и потоки, я могу перейти к некоторым более продвинутым приемам запуска процессов под WinDBG. Коман
338 ЧАСТЬ II Производительная отладка
да .CREATE (Create Process — создать процесс) позволяет вам запускать произволь ные процессы. Это весьма полезно, если необходимо отлаживать различные ас пекты COM+ или других кросс процессных приложений. Основные параметры
.CREATE — полный путь к процессу, который надо запустить, и параметры коман дной строки этого процесса. Так же, как и при обычном запуске любого процес са, лучше заключить путь и имя процесса в кавычки, дабы избежать проблем с про белами. Ниже показано применение .CREATE для запуска программы Solitaire на одной из моих машин для программирования:
.create "e:\winnt\system32\sol.exe"
После нажатия клавиши Enter WinDBG сообщает, что процесс будет создан для дальнейшего исполнения. Это значит, что WinDBG должен разрешить «раскрутить ся» схеме отладчика, чтобы обработать уведомление о создании процесса. WinDBG уже сделал вызов CreateProcess, но отладчик его еще не видит! Нажав F5, вы осво бодите цикл отладки. Появляется уведомление о создании процесса, и WinDBG остановится на точке прерывания загрузчика. Если вы применяете команду | для просмотра процессов, WinDBG покажет процессы, запущенные .CREATE с пометкой «create», как будто вы запустили сеанс отладчика, указав этот процесс.
Присоединение к процессам и отсоединение от них
При отладке уже работающего процесса вам пригодится команда .ATTACH (Attach to Process — присоединиться к процессу). Сейчас мы обсудим все аспекты присо единения к процессу. В следующем разделе мы обсудим неразрушающее присое динение, при котором процесс не работает в цикле отладчика.
Команда .ATTACH требует указания ID процесса для присоединения к процессу. Если вы располагаете физическим доступом к машине, на которой выполняется процесс, можно увидеть ID процесса в диспетчере задач (Task Manager), но при удаленной отладке это сделать трудновато. К счастью, разработчики WinDBG до бавили команду .TLIST (List Process Ids — вывести ID процессов) для вывода спис ка исполняющихся на машине процессов. Если вы отлаживаете сервисы Win32, укажите параметр –v команды .TLIST, чтобы увидеть, какие сервисы в каких про цессах выполняются. Вывод .TLIST выглядит так:
0n1544 e:\winnt\system32\sol.exe
0n1436 E:\Program Files\Windows NT\Pinball\pinball.exe
0n2120 E:\WINNT\system32\winmine.exe
Впервые увидев этот вывод, я подумал, что в этой команде ошибка и кто то слу чайно напечатал «0n» вместо «0x». Однако позже я узнал, что 0n — такой же стандар тный префикс ANSI для десятичных значений, как 0x для шестнадцатиричных.
Располагая десятичным значением ID процесса, вы передаете его как параметр команде .ATTACH (если, конечно, вы используете префикс 0n, или это не будет ра ботать). Так же, как и при создании процесса, WinDBG что либо скажет о том, что подключение произойдет при следующем исполнении, поэтому вам нужно нажать F5 для запуска цикла отладки. С этого момента вы отлаживаете процесс, к кото рому присоединились. Разница только в том, что | пометит процесс как «attach» в своем выводе.
ГЛАВА 8 Улучшенные приемы для неуправляемого кода с использованием WinDBG |
339 |
|
|
При отладке под Windows XP/Server 2003 для освобождения отладчика служит команда .DETACH (Detach from Process — отсоединиться от процесса). Так как это работает только в текущем процессе, вам нужно переключиться на процесс, от которого хотите отсоединиться, прежде чем исполните команду .DETACH. В любой момент вы можете снова присоединиться к процессу для полной его отладки.
Если вы просто хотите присоединиться к процессу сразу после запуска WinDBG, когда еще не открыто окно Command, нажмите F6 либо выберите из меню File Attach To A Process (присоединиться к процессу). В появившемся диалоговом окне Attach To Process (присоединиться к процессу) можно раскрыть узлы дерева для просмотра командных строк процессов. Если, как случается, процесс содержит сервисы Win32, вы их тоже увидите. Выбрав процесс, щелкните OK, и вы погру зитесь в отладку.
Неразрушающее присоединение
Только что описанное полное присоединение прекрасно, так как вы располагае те доступом ко всем способам отладки, например, к точкам прерывания. Однако в Microsoft Windows 2000 процесс, запущенный однажды под отладчиком, будет работать под ним вечно. Это не всегда удобно, если вы пытаетесь отлаживать рабочие серверы, так как вам придется оставлять кого то зарегистрированным на этом сервере с полными правами администратора, чтобы мог работать WinDBG, не говоря уж о замедлении процессов отладчиком. К счастью, в Windows XP/Server 2003 можно отсоединяться от отлаживаемых процессов (то, о чем я просил еще во времена Microsoft Windows 3.1!).
Чтобы сделать промышленную отладку под Windows 2000 попроще, WinDBG предлагает неразрушающее присоединение. WinDBG приостанавливает процесс, чтобы вы могли исследовать его с помощью команд, но вы не можете осуществ лять обычные задачи отладки, скажем, устанавливать точки прерывания. Это при емлемый компромисс: вы можете получить полезную информацию, например, состояние описателей, причем затем процесс будет работать на полной скорости.
Возможно, самый лучший вариант неразрушающей отладки — использование отдельного экземпляра WinDBG. Как вы скоро увидите, для продолжения процес са, возобновляющего все потоки, рабочее пространство нужно закрыть. Если вы уже отлаживаете процессы, WinDBG должен будет сразу остановить эти процес сы. Прежде чем выбрать отлаживаемый процесс, в нижней части диалогового окна Attach To Process (рис. 8 4) установите флажок Noninvasive (неразрушающее), и вы не попадете в полную отладку.
Когда вы щелкнете OK, WinDBG будет готов к нормальной отладке. Однако предупреждение в верхней части окна Command, показанное здесь, поможет вам вспомнить, что вы делаете:
WARNING: Process 1612 is not attached as a debuggee
The process can be examined but debug events will not be received
Внимание: Процесс 1612 не присоединен как отлаживаемый процесс.
Процесс доступен для исследования, но события отладки не обрабатываются.
340 ЧАСТЬ II Производительная отладка
Рис. 8 4. Подготовка к неразрушающей отладке
Присоединившись, можно исследовать в процессе что угодно. Завершив иссле дование, надо освободить процесс, чтобы продолжить его исполнение. Лучший способ освободить отлаживаемую программу — дать команду Q (Quit — завершить). Она закроет рабочее пространство, но WinDBG продолжит работать — потом вы сможете опять присоединиться. .DETACH тоже работает, но вам придется завершить WinDBG, так как нет способа присоединиться к процессу снова в этом же сеансе.
Общие вопросы отладки в окне Command
В этом разделе я объясню, как начать отладку с помощью WinDBG, и расскажу о ключевых командах, позволяющих эффективно выполнять отладку из окна Com mand. Вы узнаете также о некоторых хитростях. Пересказывать документацию я не буду, но прочитать ее настоятельно рекомендую.
Просмотр и вычисление переменных
Просмотр локальных переменных — это вотчина команды DV (Display Local Variables
— отобразить локальные переменные). Единственное, что слегка путает при ра боте с WinDBG, — это просмотр локальных переменных вверх по стеку. На са мом деле эта команда исполняется в виде нескольких команд, которые делают то, что происходит автоматически при щелчке в окне Call Stack (стек вызовов).
Первый шаг — дать команду K (Display Stack Backtrace — отобразить обратную трассировку стека) с модификатором N, чтобы увидеть стек вызовов с номерами фреймов в самой левой колонке каждого элемента стека (между прочим, моя любимая команда отображения стека — KP — показывает стек со значениями па раметров, передаваемых функциям в каждом элемента стека). Номера фреймов обычны в том смысле, что вершина стека всегда имеет номер 0, следующий эле мент — 1 и т. д. Эти номера фреймов понадобятся вам, чтобы указать команде .FRAME (Set Local Context — установить локальный контекст) переместиться вниз по сте ку. Значит, чтобы просмотреть локальные переменные функции, которая вызвала
