Bagikan melalui


Penelusuran kesalahan proses jarak jauh langsung Linux

Artikel ini menjelaskan cara membuat koneksi WinDbg langsung ke Linux. Penelusuran kesalahan proses jarak jauh langsung di Linux memerlukan WinDbg versi 1.2402.24001.0 atau lebih tinggi.

Debugger GNU - GDBServer, digunakan di Linux untuk mendukung koneksi WinDbg. Untuk informasi selengkapnya tentang GDBServer, lihat https://en.wikipedia.org/wiki/Gdbserver. Satu tempat untuk melihat dokumentasi untuk penelusuran kesalahan gdb jarak jauh ada di sini - https://sourceware.org/gdb/current/onlinedocs/gdb#Remote-Debugging

Contoh di sini menggunakan Subsistem Windows untuk Linux (WSL), tetapi implementasi Linux lainnya juga dapat digunakan.

Jenis WinDbg dari penelusuran kesalahan proses jarak jauh

Ada dua metode utama untuk melakukan penelusuran kesalahan jarak jauh dengan WinDbg - Server proses atau server koneksi KD. Server proses digunakan untuk penelusuran kesalahan mode pengguna; Server koneksi KD digunakan untuk penelusuran kesalahan mode kernel. Lihat Server Proses (Mode Pengguna) dan Server Koneksi KD (Mode Kernel) untuk informasi umum tentang jenis koneksi WinDbg ini.

Ada dua cara untuk mulai men-debug proses mode pengguna Linux. Anda dapat memulai gdbserver pada proses tertentu atau Anda dapat memulai gdbserver sebagai server proses yang dapat mencantumkan dan melampirkan ke proses yang ada. Ini mirip seperti server proses DbgSrv (dbgsrv.exe) di Windows. Untuk informasi selengkapnya, lihat Mengaktifkan Server Proses.

Debugging proses Linux mode pengguna

Dimungkinkan untuk terhubung ke proses mode pengguna tunggal tertentu, atau dalam multi-mode, untuk melihat semua proses dalam daftar dan memilih salah satu untuk disambungkan. Kedua metode dijelaskan dalam topik ini. Kedua metode berbagi sintaks string koneksi yang sama, dijelaskan berikutnya.

Format untuk string koneksi gdbserver

Format yang digunakan untuk menyambungkan ke gdbserver adalah "protocol:arguments" di mana argumen adalah daftar "argument=value" yang dipisahkan koma. Untuk koneksi gdbserver mode pengguna, protokolnya adalah gdb dan kumpulan argumen adalah sebagai berikut.

server=<address> - Wajib: menunjukkan alamat IP gdbserver untuk disambungkan.

port=<port> - Wajib: menunjukkan nomor port gdbserver untuk disambungkan.

threadEvents=<true|false> - Opsional: menunjukkan apakah peristiwa utas untuk versi gdbserver ini berfungsi dengan benar dalam mode berhenti.

Ada masalah dalam rilis gdbserver saat ini, di mana mengaktifkan peristiwa utas dengan server dalam mode berhenti (yang digunakan WinDbg) akan menyebabkan gdbserver mengalami crash. Jika nilai ini salah (nilai default), peristiwa mulai dan hentikan utas akan disintesis tetapi dapat muncul secara signifikan lebih lambat dari waktu aktual pembuatan/penghancuran utas. Ketika perbaikan untuk ini tersedia di gdbserver, peristiwa aktual dapat diaktifkan melalui opsi ini.

Menyambungkan ke Proses Mode Pengguna Tunggal

Bagian ini menjelaskan cara mengidentifikasi dan menyambungkan ke proses mode pengguna tunggal di Linux, menggunakan WinDbg.

WSL (Subsistem Windows untuk Linux)

Contoh di sini menggunakan WSL (Subsistem Windows untuk Linux), tetapi implementasi Linux lainnya dapat digunakan. Untuk informasi tentang menyiapkan dan menggunakan WSL, lihat:

Pilih proses yang diinginkan

Mencantumkan proses di Linux menggunakan ps -A perintah untuk menentukan proses yang sedang berjalan untuk disambungkan.

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

Dalam contoh panduan ini, kita akan terhubung ke python3.

Menemukan alamat IP sistem target

Jika menyambungkan ke target linux jarak jauh, gunakan perintah seperti ip route showuntuk menentukan alamat IP eksternal.

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

Dalam panduan ini, kami akan terhubung ke WSL yang berjalan pada PC yang sama, dan akan menggunakan alamat IP localhost.

Lampirkan GDBServer ke proses yang dipilih

Pada konsol linux WSL, masukkan gdbserver localhost:1234 python3 untuk memulai gdbserver pada port 1234, dan lampirkan ke proses python3.

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

Untuk beberapa lingkungan linux, perintah mungkin perlu dijalankan sebagai administrator, misalnya menggunakan sudo - sudo gdbserver localhost:1234 python3. Berhati-hatilah dengan mengaktifkan akses tingkat root administrator debugger dan hanya gunakan ini saat diperlukan.

Membuat koneksi server proses di WinDbg

Buka WinDbg, dan pilih "File / Sambungkan ke Debugger Jarak Jauh" dan masukkan string protokol untuk koneksi. Untuk contoh ini, kita akan menggunakan: gdb:server=localhost,port=1234.

cuplikan layar layar WinDbg Mulai penelusuran kesalahan memperlihatkan string koneksi.

Setelah Anda mengklik tombol OK, debugger harus terhubung ke gdbserver dan Anda harus berada di hentian mulai proses awal.

Setelah Anda berada di titik henti awal, Anda dapat menekan 'g' beberapa kali. Anda akan mendapatkan pesan beban modul (dan gaya sxe "break on module load" peristiwa harus berfungsi dengan baik).

Perhatikan bahwa mungkin perlu waktu sejenak untuk sampai ke titik itu, karena simbol debug dimuat ke dalam cache. Selain mencari simbol dan biner melalui server simbol atau jalur pencarian lokal Anda, integrasi GDBServer memiliki kemampuan menarik file-file ini dari sistem file jarak jauh jika tidak dapat ditemukan melalui symsrv atau secara lokal. Ini biasanya merupakan operasi yang jauh lebih lambat daripada mendapatkan simbol dari symsrv atau jalur pencarian lokal tetapi membuat pengalaman keseluruhan menjadi lebih baik dengan menemukan simbol yang sesuai.

Gunakan perintah tumpukan k untuk mencantumkan tumpukan. Ini menunjukkan modul python3, jadi ini mengonfirmasi bahwa kami men-debug python3 di Linux menggunakan 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

Pada titik ini, Anda harus dapat melakukan hampir semua yang dapat dilakukan menggunakan WinDbg yang terpasang pada debugger Windows jarak jauh melalui server proses jarak jauh. Anda dapat melangkah, debug tingkat sumber, mengatur titik henti, memeriksa lokal, dll..

Setelah Anda selesai men-debug, gunakan CTRL+D untuk keluar dari jendela gbdserver di WSL.

Menyambungkan ke Server Proses

Selain menyambungkan ke satu proses melalui mode pengguna GDBServer, Anda dapat menyiapkannya sebagai server proses dan mencantumkan dan melampirkan ke proses yang ada pada sistem. Untuk melakukan ini, gdbserver dimulai dengan argumen baris perintah "--multi" - gdbserver --multi localhost:1234

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

Untuk menyambungkan ke server proses, pilih "File / Sambungkan ke server proses" di WinDbg dan masukkan string protokol yang sama seperti yang Anda lakukan dengan contoh gdbserver proses tunggal di atas:

gdb:server=localhost,port=1234

Setelah Anda mengklik tombol "OK", Anda harus terhubung ke gdbserver sebagai server proses. Seperti halnya dbgsrv, Anda dapat menelurkan proses baru atau Anda dapat mencantumkan proses yang ada dan melampirkan ke proses tersebut.

Dalam contoh ini, gunakan opsi "Lampirkan ke proses".

cuplikan layar layar WinDbg Mulai penelusuran kesalahan memperlihatkan lampirkan ke proses dengan 20 atau lebih proses yang tercantum.

Perhatikan bahwa Anda akan melihat banyak hal yang sama yang terlihat untuk proses Windows (termasuk PID, pengguna, dan baris perintah). Beberapa kolom dalam dialog "lampirkan ke proses" tidak relevan dengan Linux dan tidak akan berisi data.

Mengakhiri sesi

Gunakan CTRL+D untuk keluar dari jendela gbdserver di WSL dan pilih hentikan penelusuran kesalahan di WinDbg. Untuk mengakhiri sesi, dalam beberapa kasus Anda mungkin perlu keluar dari debugger.

Menyambungkan kembali ke server proses

WinDbg mengenali "server proses" versus "target tunggal" melalui apakah gdbserver dilampirkan ke proses atau tidak. Jika Anda melampirkan ke beberapa proses, biarkan dibekukan, tutup debugger, dan coba sambungkan kembali ke server proses, dalam semua kemungkinan, kami tidak akan mengenalinya sebagai server proses. Dalam situasi ini, mulai ulang target gdbserver dan sambungkan kembali debugger.

Fungsionalitas Linux WinDbg

Meskipun sebagian besar fungsionalitas debugger akan berfungsi seperti yang diharapkan" dalam debugging core dump (misalnya: stack walking, simbol, informasi jenis, variabel lokal, pembongkaran, dll...), penting untuk dicatat bahwa seluruh toolchain debugging belum mengetahui ELF, DWARF, dan perbedaan yang dihasilkan dari semantik Windows. Beberapa perintah dalam debugger saat ini dapat mengakibatkan output yang tidak terduga. Misalnya, lm masih akan menampilkan informasi yang salah untuk modul ELF seperti yang diharapkan dan mengurai header PE secara manual.

Mode Kernel Linux melalui EXDI

Debugger Windows mendukung penelusuran kesalahan kernel menggunakan EXDI. Ini memungkinkan penelusuran kesalahan berbagai perangkat keras dan sistem operasi. Untuk informasi umum tentang menyiapkan konfigurasi dan pemecahan masalah koneksi EXDI, lihat Mengonfigurasi Exdi Debugger Transport.

Untuk informasi tentang cara menyiapkan Debugging Mode Kernel QEMU menggunakan EXDI, lihat Menyiapkan Debugging Mode Kernel QEMU Menggunakan EXDI.

Simbol dan Sumber Linux

Bagian ini menjelaskan penggunaan dasar dan ketersediaan simbol Linux. Untuk informasi selengkapnya, lihat Simbol dan sumber Linux serta Akses Yang Diperluas Kode Sumber.

Server simbol DebugInfoD

Memulai WinDbg versi 1.2104, perintah jalur sumber (.srcpath, .lsrcpath (Set Source Path)) mendukung pengambilan file dari server DebugInfoD melalui DebugInfoD* tag.

Tag DebugInfoD* dapat menunjuk ke satu atau beberapa server DebugInfoD dengan setiap URL server diformat sebagai https://domain.com dan dipisahkan oleh *. Server akan dicari dalam urutan yang sama seperti yang tercantum di jalur sumber dan file akan diambil dari URL pertama yang cocok. Untuk informasi selengkapnya, lihat Kode Sumber Akses yang Diperluas.

Misalnya Anda dapat menggunakan perintah .sympath (Atur Jalur Simbol) untuk mengatur jalur DebugInfoD seperti ini.

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

Untuk informasi umum tentang mengatur jalur simbol, lihat Menggunakan Simbol.

Untuk menampilkan informasi tentang simbol yang sedang dimuat, gunakan !sym noisy. Untuk informasi selengkapnya, lihat !sym.

Juga didukung adalah pengunduhan otomatis sumber dari server DebugInfoD yang mendukung pengembalian jenis artefak tersebut. Anda dapat, pada dasarnya melakukan:

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

Untuk informasi selengkapnya tentang bekerja dengan simbol DWARF dan utilitas simbol Linux, seperti !sourcemap dan , lihat simbol dan sumber!diesym Linux.

Panduan aplikasi C++

  1. Gunakan editor teks (seperti nano atau vi) untuk membuat file C++Anda. Contohnya:

nano DisplayGreeting.cpp

  1. Di editor teks, tulis program C++ Anda. Berikut adalah program sederhana yang menampilkan salam, yang perlu di-debug:
#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. Simpan (CTRL-O) dan keluar (CTRL-X) editor nano.

  2. Kompilasi file C++ menggunakan g++. Opsi -o digunakan untuk menentukan nama file output, dan opsi -g menghasilkan file simbol:

g++ DisplayGreeting.cpp -g -o DisplayGreeting

  1. Jika tidak ada kesalahan dalam kode Anda, perintah g++ akan membuat file yang dapat dieksekusi bernama DisplayGreeting di direktori Anda.

  2. Anda dapat menjalankan program menggunakan perintah berikut:

./DisplayGreeting

  1. Menekan tombol kembali menampilkan pesan di aplikasi. Melihat output, sepertinya Salam sedang dipotong, dan "????" ditampilkan sebagai gantinya.

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

Penelusuran Kesalahan DisplayGreeting

  1. Setelah kode siap dijalankan, kita dapat memulai aplikasi menggunakan gdbserver.

gdbserver localhost:1234 DisplayGreeting

  1. Buka WinDbg, dan pilih "File / Sambungkan ke Debugger Jarak Jauh" dan masukkan string protokol untuk koneksi. Untuk contoh ini, kita akan menggunakan: gdb:server=localhost,port=1234.

  2. Setelah tersambung, output harus menunjukkan bahwa ia mendengarkan pada port 1234 dan koneksi debugging jarak jauh dibuat.

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

Seperti disebutkan sebelumnya, untuk beberapa lingkungan Linux perintah mungkin perlu dijalankan sebagai administrator, biasanya menggunakan sudo. Berhati-hatilah dengan mengaktifkan akses tingkat root administrator debugger dan hanya gunakan ini saat diperlukan.

Menambahkan jalur sumber dan simbol ke sesi debugger

Untuk mengatur titik henti dan melihat kode sumber dan variabel, atur simbol dan jalur sumber. Untuk informasi umum tentang mengatur jalur simbol, lihat Menggunakan Simbol.

Gunakan .sympath untuk menambahkan jalur simbol ke sesi debugger. Dalam contoh ini, kode berjalan di lokasi ini di WSL Linux Ubuntu, untuk pengguna bernama Bob.

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

Di WSL, direktori ini memetakan ke lokasi OS Windows dari: C:\Users\Bob\

Jadi kedua perintah ini digunakan.

.sympath C:\Users\Bob\

.srcpath C:\Users\Bob\

Untuk informasi selengkapnya tentang sistem file WSL, lihat Izin File untuk WSL.

  1. Untuk mendapatkan manfaat dari simbol OS Linux tambahan, tambahkan simbol DebugInfoD menggunakan lokasi .sympath, seperti ini.

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

  1. Juga didukung adalah pengunduhan otomatis sumber dari server DebugInfoD yang mendukung pengembalian jenis artefak tersebut. Untuk memanfaatkan ini, tambahkan server elfutils menggunakan .srcpath.

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

Menetapkan titik henti

Atur titik henti di utama aplikasi 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

Gunakan opsi perintah Go atau menu untuk memulai ulang eksekusi kode.

Memuat kode sumber

Gunakan perintah .reload untuk memuat ulang simbol.

lm Gunakan perintah untuk mengonfirmasi bahwa kami menjalankan aplikasi 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

Setelah perintah memicu akses ke kode salam tampilan, perintah akan ditampilkan di WinDbg.

cuplikan layar kode DisplayGreeting.cpp di WinDbg dengan titik henti diatur pada baris 19, wprint

Gunakan perintah 'k' untuk mencantumkan tumpukan.

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```

Gunakan perintah dx untuk melihat salam variabel lokal. Perhatikan bahwa ukurannya adalah 50.

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

Lihat kode dan perhatikan bahwa 50, mungkin bukan ukuran yang cukup untuk pesan salam.

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

Konfirmasikan ini dengan memperluas variabel lokal untuk salam dan melihat bahwa salam dipotong.

Pemecahan masalah koneksi gdbserver

--debug Gunakan opsi untuk menampilkan informasi tambahan di konsol gdbserver untuk mengumpulkan informasi selengkapnya tentang status koneksi. Misalnya untuk memulai server proses, gunakan perintah ini.

gdbserver --debug --multi localhost:1234

Lihat juga

Simbol dan sumber Linux

Akses Yang Diperluas Kode Sumber

Debuginfod ELFUTILS

Memilih Metode Debugging Jarak Jauh Terbaik