Поделиться через


Отладка удаленного процесса Linux

В этой статье описывается, как установить динамическое подключение WinDbg к Linux. Для отладки удаленного процесса в Linux требуется WinDbg версии 1.2402.24001.0 или более поздней.

Отладчик GNU — GDBServer используется в Linux для поддержки подключения WinDbg. Дополнительные сведения о GDBServer см. в статье https://en.wikipedia.org/wiki/Gdbserver. Здесь можно просмотреть документацию по удаленной отладке gdb. https://sourceware.org/gdb/current/onlinedocs/gdb#Remote-Debugging

В примерах здесь используется подсистема Windows для Linux (WSL), но также можно использовать другие реализации Linux.

Типы WinDbg удаленной отладки процессов

Существует два основных метода выполнения удаленной отладки с помощью WinDbg — сервера обработки или сервера подключения KD. Серверы обработки используются для отладки в пользовательском режиме; Серверы подключения KD используются для отладки в режиме ядра. Общие сведения об этих типах подключений WinDbg см. в разделе "Серверы обработки" (режим пользователя) и серверы Подключение ion server (режим ядра).

Существует два способа запуска отладки процессов пользовательского режима Linux. Вы можете запустить gdbserver в определенном процессе или запустить gdbserver как сервер обработки, который может перечислять и присоединять к существующим процессам. Это так же, как сервер обработки DbgSrv (dbgsrv.exe) в Windows. Дополнительные сведения см. в разделе "Активация сервера обработки".

Отладка процесса Linux в пользовательском режиме

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

Формат строка подключения gdbserver

Формат, используемый для подключения к gdbserver, — "protocol:arguments", где аргументы — это разделенный запятыми список "argument=value". Для подключения gdbserver в пользовательском режиме протокол — gdb, и набор аргументов выглядит следующим образом.

server=<address> — обязательный: указывает IP-адрес gdbserver для подключения.

port=<port> — Обязательный: указывает номер порта gdbserver для подключения.

threadEvents=<true|false> — Необязательный: указывает, работают ли события потока для этой версии gdbserver правильно в режиме остановки.

В текущих выпусках gdbserver возникает проблема, при которой включение событий потока с сервером в режиме остановки (которое использует WinDbg) приведет к сбою gdbserver. Если это значение равно false (значение по умолчанию), события запуска и остановки потока будут синтезированы, но могут отображаться значительно позже фактического времени создания или уничтожения потока. Если исправление для этого доступно в gdbserver, фактические события можно включить с помощью этого параметра.

Подключение процесс единого пользовательского режима

В этом разделе описывается, как определить и подключиться к одному процессу пользовательского режима в Linux с помощью WinDbg.

WSL (подсистема Windows для Linux)

В примерах здесь используется WSL (подсистема Windows для Linux), но можно использовать другие реализации Linux. Сведения о настройке и использовании WSL см. в следующей статье:

Выберите нужный процесс

Вывод списка процессов в Linux с помощью ps -A команды для определения выполняемого процесса для подключения.

user1@USER1:/mnt/c/Users/USER1$ ps -A
    PID TTY          TIME CMD
    458 pts/1    00:00:00 bash
    460 ?        00:00:00 rtkit-daemon
    470 ?        00:00:00 dbus-daemon
    482 ?        00:00:19 python3
   1076 ?        00:00:00 packagekitd
   1196 pts/0    00:00:00 ps

В этом примере пошагового руководства мы подключимся к Python3.

Поиск IP-адреса целевой системы

При подключении к удаленному целевому объекту Linux используйте команду, например ip route show, чтобы определить внешний IP-адрес.

user1@USER1:/mnt/c/Users/USER1$ ip route show
default via 192.168.1.1 dev enp3s0 proto dhcp metric 100
172.25.144.0/24 dev enp3s0 proto kernel scope link src 192.168.1.107 metric 100

В этом пошаговом руководстве мы подключимся к WSL, работающему на одном компьютере, и будем использовать IP-адрес localhost.

Присоединение GDBServer к выбранному процессу

В консоли Linux WSL введите gdbserver localhost:1234 python3 файл gdbserver через порт 1234 и подключите его к процессу Python3.

USER1@USER1:/mnt/c/Users/USER1$ gdbserver localhost:1234 python3
Process python3 created; pid = 1211
Listening on port 1234

Для некоторых сред Linux может потребоваться выполнить команду от имени администратора, например с помощью sudo - sudo gdbserver localhost:1234 python3. Используйте осторожность, чтобы включить доступ к корневому уровню администратора отладчика и использовать его только в том случае, если это необходимо.

Создание подключения сервера обработки в WinDbg

Откройте WinDbg и выберите "Файл / Подключение в удаленный отладчик" и введите строку протокола для подключения. В этом примере мы будем использовать: gdb:server=localhost,port=1234

Снимок экрана: экран начальной отладки WinDbg с строка подключения.

После нажатия кнопки "ОК" отладчик должен подключиться к gdbserver и начать начальный процесс.

Когда вы находитесь в начальной точке останова, вы можете нажать клавишу G несколько раз. Вы получите сообщения о загрузке модуля (и стиль sxe "разрыв при загрузке модуля" должен работать должным образом).

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

Используйте команду k stacks для перечисления стека. В нем показаны модули Python3, поэтому это подтверждает, что мы отладим python3 в Linux с помощью WinDbg.

0:000> k
 # Child-SP          RetAddr               Call Site
00 00007fff`ffffce10 00007fff`f786d515     libc_so!_select+0xbd
01 00007fff`ffffce80 00005555`55601ce8     readline_cpython_310_x86_64_linux_gnu!PyInit_readline+0xac5
02 00007fff`ffffcf60 00005555`556f06a1     python3!PyOS_Readline+0x109
03 00007fff`ffffcfa0 00005555`556eee7e     python3!PyFrame_LocalsToFast+0x62a1
04 00007fff`ffffd000 00005555`556edcf0     python3!PyFrame_LocalsToFast+0x4a7e
05 00007fff`ffffdb80 00005555`557a18e9     python3!PyFrame_LocalsToFast+0x38f0
06 00007fff`ffffdc00 00005555`557a1470     python3!PyCodec_LookupError+0xb09
07 00007fff`ffffdc50 00005555`557b89dc     python3!PyCodec_LookupError+0x690
08 00007fff`ffffdc70 00005555`5560b42f     python3!PyUnicode_Tailmatch+0xc6c
09 00007fff`ffffdcb0 00005555`5560b012     python3!PyRun_InteractiveLoopObject+0x4e0
0a 00007fff`ffffdd50 00005555`557b7678     python3!PyRun_InteractiveLoopObject+0xc3
0b 00007fff`ffffdda0 00005555`555f55c8     python3!PyRun_AnyFileObject+0x68
0c 00007fff`ffffddd0 00005555`555ea6e8     python3!PyRun_AnyFileExFlags+0x4f
0d 00007fff`ffffde00 00005555`55780cad     python3!Py_str_to_int+0x2342a
0e 00007fff`ffffdef0 00007fff`f7c7cd90     python3!Py_BytesMain+0x2d
0f 00007fff`ffffdf20 00007fff`f7c7ce40     libc_so!_libc_init_first+0x90
10 00007fff`ffffdfc0 00005555`55780ba5     libc_so!_libc_start_main+0x80
11 00007fff`ffffe010 ffffffff`ffffffff     python3!start+0x25
12 00007fff`ffffe018 00000000`00000000     0xffffffff`ffffffff

На этом этапе вы сможете сделать почти все, что можно сделать с помощью WinDbg, подключенного к удаленному отладчику Windows на удаленном сервере обработки. Вы можете выполнить шаг, отладку на уровне источника, задать точки останова, проверить локальные и т. д.

После завершения отладки используйте CTRL+D, чтобы выйти из окна gbdserver в WSL.

Подключение на сервер обработки

Помимо подключения к одному процессу через GDBServer пользовательского режима, вы можете настроить его как сервер обработки и добавить к существующим процессам в системе. Для этого gdbserver запускается с аргументом командной строки --multi . gdbserver --multi localhost:1234

user1@USER1:/mnt/c/Users/USER1$ sudo gdbserver --multi localhost:1234
Listening on port 1234

Чтобы подключиться к серверу обработки, выберите "Файл / Подключение для обработки сервера" в WinDbg и введите ту же строку протокола, что и в примере с одним процессом gdbserver выше:

gdb:server=localhost,port=1234

После нажатия кнопки "ОК" необходимо подключиться к gdbserver в качестве сервера обработки. Как и при использовании dbgsrv, можно либо создать новый процесс, либо перечислить существующие процессы и подключить к нему.

В этом примере используйте параметр "Присоединить к процессу".

Снимок экрана: экран начальной отладки WinDbg, показывающий подключение к процессу с 20 или таким образом перечисленными процессами.

Обратите внимание, что вы увидите множество одинаковых элементов, видимых для процессов Windows (включая PID, пользователя и командную строку). Некоторые столбцы в диалоговом окне "Присоединение к процессу" не относятся к Linux и не будут содержать данные.

Завершение сеанса

Нажмите клавиши CTRL+D, чтобы выйти из окна gbdserver в WSL и остановить отладку в WinDbg. Чтобы завершить сеанс, в некоторых случаях может потребоваться выйти из отладчика.

Повторное подключение к серверу обработки

WinDbg распознает "сервер обработки" и "один целевой объект" через присоединение gdbserver к процессу или нет. Если вы подключаетесь к некоторым процессам, оставьте его замороженным, закройте отладчик и попытаетесь повторно подключиться к серверу обработки, по всей вероятности, мы не будем распознавать его как сервер обработки. В этой ситуации перезапустите целевой gdbserver и повторно подключите отладчик.

Функции WinDbg для Linux

Хотя большая часть функциональных возможностей отладчика будет работать должным образом", при отладке основных дампов (например, стека, символов, сведений о типах, локальных переменных, дизассембли и т. д.), важно отметить, что вся цепочка инструментов отладки еще не была осведомлена о ELF, DWARF и результирующей разнице в семантике Windows. Некоторые команды в отладчике в настоящее время могут привести к непредвиденным выходным данным. Например, по-прежнему отображаются неверные сведения для модуля ELF, lm так как он ожидает и вручную анализирует заголовки PE.

Режим ядра Linux через EXDI

Отладчик Windows поддерживает отладку ядра с помощью EXDI. Это позволяет выполнять отладку различных аппаратных и операционных систем. Общие сведения о настройке и устранении неполадок подключений EXDI см. в разделе "Настройка транспорта отладчика EXDI".

Сведения о настройке отладки режима ядра QEMU с помощью EXDI см. в статье Настройка отладки режима ядра QEMU с помощью EXDI.

Символы и источники Linux

В этом разделе описаны основные возможности использования и доступности символов Linux. Дополнительные сведения см. в разделе "Символы и источники Linux" и "Расширенный доступ к исходному коду".

Серверы символов DebugInfoD

Начиная с WinDbg версии 1.2104 команда исходного пути (Srcpath, .lsrcpath (Set Source Path)) поддерживает извлечение файлов из серверов DebugInfoD с помощью тега DebugInfoD* .

Тег DebugInfoD* может указывать на один или несколько серверов DebugInfoD с каждым URL-адресом сервера, отформатированным как https://domain.com и разделенным *. Серверы будут искать в том же порядке, что и в исходном пути, и файлы будут получены из первого соответствующего URL-адреса. Дополнительные сведения см. в статье "Расширенный доступ к исходному коду".

Например, можно использовать команду Sympath (Задать путь к символам), чтобы задать путь DebugInfoD, как показано ниже.

.sympath+ DebugInfoD*https://debuginfod.elfutils.org

Общие сведения о настройке пути символов см. в разделе "Использование символов".

Чтобы отобразить сведения о загружаемых символах, используйте !sym noisy. Дополнительные сведения см. в разделе !sym.

Также поддерживается автоматическая загрузка источников с серверов DebugInfoD, которые поддерживают возврат этого типа артефакта. Вы можете, по сути, сделать следующее:

.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

Дополнительные сведения о работе с символами DWARF и служебными программами символов Linux, такими как !sourcemap и !diesym, см. в разделе "Символы и источники Linux".

Пошаговое руководство по приложению C++

  1. Для создания файла C++ используйте текстовый редактор (например, nano или vi). Например:

nano DisplayGreeting.cpp

  1. В текстовом редакторе напишите программу C++. Ниже приведена простая программа, которая отображает приветствия, которая должна быть отлаживаема:
#include <array>
#include <cwchar>
#include <cstdio>
#include <iostream>
using namespace std;

void GetCppConGreeting(wchar_t* buffer, size_t size)
{
    wchar_t const* const message = L"HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL DEBUGGING!";
    wcsncpy(buffer, message, size);
}

int main()
{
    std::array<wchar_t, 50> greeting{};
    GetCppConGreeting(greeting.data(), greeting.size());

    cin.get();
    wprintf(L"%ls\n", greeting.data());

    return 0;
}
  1. Сохраните (CTRL-O) и закройте (CTRL-X) редактор nano.

  2. Скомпилируйте файл C++ с помощью g++. Параметр -o используется для указания имени выходного файла, а параметр -g создает файл символов:

g++ DisplayGreeting.cpp -g -o DisplayGreeting

  1. Если в коде нет ошибок, команда g++ создаст исполняемый файл с именем DisplayGreeting в каталоге.

  2. Вы можете запустить программу с помощью следующей команды:

./DisplayGreeting

  1. При нажатии клавиши возврата отображается сообщение в приложении. Глядя на выходные данные, он выглядит так, как приветствие усечено, а вместо этого отображается "????".

HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YO????

Отладка DisplayGreeting

  1. Когда код будет готов к выполнению, мы можем запустить приложение с помощью gdbserver.

gdbserver localhost:1234 DisplayGreeting

  1. Откройте WinDbg и выберите "Файл / Подключение в удаленный отладчик" и введите строку протокола для подключения. В этом примере мы будем использовать: gdb:server=localhost,port=1234

  2. После подключения выходные данные должны указывать на то, что он прослушивается через порт 1234 и устанавливается удаленное подключение к отладке.

Bob@Bob6:/mnt/c/Users/bob$ gdbserver localhost:1234 DisplayGreeting
Process /mnt/c/Users/bob/DisplayGreeting created; pid = 725
Listening on port 1234
Remote debugging from host 127.0.0.1, port 47700

Как упоминание ранее, для некоторых сред Linux может потребоваться выполнить команду от имени администратора, обычно используя sudo. Используйте осторожность, чтобы включить доступ к корневому уровню администратора отладчика и использовать его только в том случае, если это необходимо.

Добавление путей к источнику и символам в сеанс отладчика

Чтобы задать точки останова и просмотреть исходный код и переменные, задайте символы и исходный путь. Общие сведения о настройке пути символов см. в разделе "Использование символов".

Используйте .sympath для добавления пути символа в сеанс отладчика. В этом примере код выполняется в этом расположении в Ubuntu WSL для пользователя с именем Bob.

\\wsl$\Ubuntu\mnt\c\Users\Bob\

В WSL этот каталог сопоставляется с расположением ОС Windows: C:\Users\Bob\

Поэтому используются эти две команды.

.sympath C:\Users\Bob\

.srcpath C:\Users\Bob\

Дополнительные сведения о файловой системе WSL см. в разделе "Разрешения файлов" для WSL.

  1. Чтобы воспользоваться дополнительными символами ОС Linux, добавьте символы DebugInfoD с помощью расположения Sympath, как показано ниже.

.sympath+ DebugInfoD*https://debuginfod.elfutils.org

  1. Также поддерживается автоматическая загрузка источников с серверов DebugInfoD, которые поддерживают возврат этого типа артефакта. Чтобы воспользоваться этим, добавьте сервер elfutils с помощью Srcpath.

.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

Установка точки останова

Задайте точку останова в главной части приложения DisplayGreeting.

0:000> bp DisplayGreeting!main
0:000> bl
     0 e Disable Clear  00005555`55555225  [/mnt/c/Users/bob/DisplayGreeting.cpp @ 14]     0001 (0001)  0:**** DisplayGreeting!main

Чтобы перезапустить выполнение кода, используйте команду Go или пункт меню.

Загрузка исходного кода

Используйте команду RELOAD, чтобы перезагрузить символы.

lm Используйте команду, чтобы убедиться, что мы запускаем приложение DisplayGreeting.

0:000> lm
start             end                 module name
00005555`55554000 00005555`55558140   DisplayGreeting T (service symbols: DWARF Private Symbols)        c:\users\bob\DisplayGreeting
00007fff`f7a54000 00007fff`f7a732e8   libgcc_s_so   (deferred)             
00007fff`f7a74000 00007fff`f7b5a108   libm_so    (deferred)             
00007fff`f7b5b000 00007fff`f7d82e50   libc_so  T (service symbols: DWARF Private Symbols)        C:\ProgramData\Dbg\sym\_.debug\elf-buildid-sym-a43bfc8428df6623cd498c9c0caeb91aec9be4f9\_.debug
00007fff`f7d83000 00007fff`f7fae8c0   libstdc___so   (deferred)             
00007fff`f7fc1000 00007fff`f7fc1000   linux_vdso_so   (deferred)             
00007fff`f7fc3000 00007fff`f7ffe2d8   ld_linux_x86_64_so T (service symbols: DWARF Private Symbols)        C:\ProgramData\Dbg\sym\_.debug\elf-buildid-sym-9718d3757f00d2366056830aae09698dbd35e32c\_.debug

После активации команды доступа к отображаемого кода приветствия он будет отображаться в WinDbg.

Снимок экрана DisplayGreeting.cpp кода в WinDbg с точкой останова, установленной в строке 19, wprint

Используйте команду K для перечисления стека.

0:000> k
 # Child-SP          RetAddr               Call Site
00 00007fff`ffffde00 00007fff`f7b84d90     DisplayGreeting!main+0x1f [/mnt/c/Users/BOB/DisplayGreeting.cpp @ 15] 
01 00007fff`ffffdef0 00007fff`f7b84e40     libc_so!__libc_start_call_main+0x80 [./csu/../sysdeps/x86/libc-start.c @ 58] 
02 00007fff`ffffdf90 00005555`55555125     libc_so!__libc_start_main_impl+0x80 [./csu/../sysdeps/nptl/libc_start_call_main.h @ 379] 
03 00007fff`ffffdfe0 ffffffff`ffffffff     DisplayGreeting!start+0x25
04 00007fff`ffffdfe8 00000000`00000000     0xffffffff`ffffffff```

Используйте команду dx для просмотра приветствия локальной переменной. Обратите внимание, что размер составляет 50.

0:000> dx greeting
greeting                 : { size=50 } [Type: std::array<wchar_t, 50>]
    [<Raw View>]     [Type: std::array<wchar_t, 50>]

Просмотрите код и обратите внимание, что 50, может быть недостаточного размера для приветствия.

wchar_t const* const message = L"HELLO FROM THE WINDBG TEAM. GOOD LUCK IN ALL OF YOUR TIME TRAVEL

Подтвердите это, разверив переменную locals для приветствия и увидев, что приветствие усечено.

Устранение неполадок подключения gdbserver

--debug Используйте параметр для отображения дополнительных сведений в консоли gdbserver, чтобы получить дополнительные сведения о состоянии подключения. Например, чтобы запустить сервер обработки, используйте эту команду.

gdbserver --debug --multi localhost:1234

См. также

Символы и источники Linux

Расширенный доступ к исходному коду

Отладка ELFUTILS

Выбор оптимального метода удаленной отладки