- GDB'nin satırları, değişkenleri ve fonksiyonları okunabilir bir şekilde görüntülemesi için her zaman -go -ggdb parametresiyle derleme yapın.
- Çalıştırma, sonraki adım, adım ve devam etme komutlarıyla birlikte (basit ve koşullu) kesme noktalarını kullanarak yürütmeyi kontrol edin.
- Değişkenleri, belleği ve çağrı yığınını incelemek için yazdırma, listeleme, geri izleme ve izleme noktalarını bir araya getirir.
- Karmaşık C ve C++ programlarında hata ayıklamayı hızlandırmak için klavye kısayollarından ve bilgi komutlarından yararlanın.

C veya C++ ile programlama yapıyorsanız, er ya da geç sadece kod yazarak yakalanamayacak hatalarla karşılaşacaksınız... printf ve deneme yanılmaİşte o zaman GDB "o garip komut" olmaktan çıkar ve programınızın satır satır ne yaptığını anlamak için vazgeçilmez bir araç haline gelir.
Bu kapsamlı kılavuzda, GDB'yi kolaylıkla nasıl kullanacağınızı göreceğiz: kodunuzu hata ayıklama sembolleriyle derlemekten, nasıl yerleştireceğinize kadar. Kesme noktaları, değişkenleri inceleme, yığın üzerinde ilerleme ve klavye kısayollarından yararlanın. Tüm bunlar terminal üzerinden, pratik örnekler ve net açıklamalarla, böylece doğru şekilde hata ayıklayabilir ve hataların peşinden körü körüne koşmayı bırakabilirsiniz.
GDB nedir ve neden kullanmaya değer?
GDB (GNU Debugger), GNU ekosisteminin standart hata ayıklayıcısıdır. Esas olarak C ve C++ ile kullanılır, ancak diğer dilleri de destekler. Önceden derlenmiş yürütülebilir dosyalar üzerinde çalışır ve programınız çalışırken içine "göz atmanıza", çöktüğünde neler olduğunu görmenize ve yürütülmesini manipüle etmenize olanak tanır.
Ekranda gösterilen mesajlarla hata ayıklamanın aksine, GDB şunlara olanak tanır: Programı istediğiniz herhangi bir noktada durdurun, belleği, değişkenleri ve yığını inceleyin.Değerleri anında değiştirebilir ve yürütmeye devam edebilirsiniz. Tüm bunlar, çok eski ama inanılmaz derecede güçlü bir komut satırı arayüzü aracılığıyla yapılır.
GDB, Unix'in başlangıcından beri var ve diğer klasik araçlar gibi, gcc veya g ++Grafik arayüzü olmadan, doğrudan terminalde çalışacak şekilde tasarlanmıştır. Günümüzde pencereler ve düğmeler içeren ön uçlar mevcut, ancak temel komutlarda ustalaştıktan sonra çoğu geliştirici GDB'yi "ham haliyle" kullanarak daha hızlı sonuçlar elde ediyor.
GDB'nin öne çıktığı tipik bir senaryo, programınızın korkunç bir hatayla çöktüğü zamandır. Segmentasyon hatası (SIGSEGV)Hata ayıklayıcı olmadan, yalnızca bir şeyin geçersiz belleğe eriştiğini görürsünüz; GDB ile hangi satırda çöktüğünü, hangi fonksiyonun çalıştığını ve o anda her önemli değişkenin ne içerdiğini öğrenebilirsiniz.
GDB ile hata ayıklama için programları derleyin.

GDB'nin düzgün çalışması için, çalıştırılabilir dosyanın şunları içermesi gerekir: hata ayıklama bilgileri: Değişken adları, fonksiyonlar, kaynak kod satırları vb. Bu, kılavuzumuzda açıklandığı gibi derleyiciye belirli seçenekler eklenerek elde edilir. gcc komutu ve temel seçeneklerinin eksiksiz açıklaması.
Minimum gereksinim, seçeneğe uymaktır. -gÖrneğin, bir dosyanız varsa crash.c Bir hata sayesinde, "ikili dosya" adı verilen bir dosya oluşturabilirsiniz. crash ile:
gcc -g -o crash crash.c
Seçimi -g Programın mantığını değiştirmez; yalnızca GDB'nin kaynak kodunu, tam satırları ve yığın çerçevelerindeki gerçek değişken adlarını gösterebilmesi için meta veriler ekler. Çalıştırılabilir dosya biraz daha büyük olur, ancak kesinlikle buna değer.
C99 standardını kullanmak ve rahatça hata ayıklamaya devam etmek istediğiniz projelerde, aşağıdaki gibi seçenekleri birleştirebilirsiniz:
gcc -std=c99 -g -o test test.c
Eğer C++ kullanıyorsanız veya GDB ile daha sıkı bir entegrasyon istiyorsanız, birçok kılavuz şunu önerir: -ggdbBu hata ayıklayıcı için özel hata ayıklama bilgileri üreten komut:
g++ -ggdb -o programa main.cpp otras.cpp
Özetle: GDB ile bir ikili dosyayı hata ayıklarken, onu mutlaka derlediğinizden emin olun. -go -ggdbAksi takdirde, okunabilir fonksiyonlar ve satırlar yerine bellek adresleri ve anlaşılması güç semboller göreceksiniz.
İlk bağlantı: GDB'yi başlatın ve programınızı çalıştırın.
Sembolleri içeren çalıştırılabilir dosyayı elde ettikten sonra, GDB'yi iki şekilde başlatabilirsiniz: "boş" hata ayıklayıcıyı başlatarak veya analiz etmek istediğiniz ikili dosyayı belirterek. İkinci yöntem daha yaygındır. Çalıştırılabilir dosyayı tek bir adımda başlatıp hata ayıklayabilirsiniz..
Örneğin, bir ikili dosyayı yüklemek ve hata ayıklamak için... crash:
gdb crash
Ekranda GDB sürümü, telif hakkı ve lisans bildirimi içeren bir başlık ve ardından tipik bir komut istemi göreceksiniz:
(gdb)
Bu komut isteminden programınızı şu komutla çalıştırabilirsiniz. koşmak (veya basitçe r):
(gdb) run
Starting program: ./crash
Eğer programınız standart girdi bekliyorsa, GDB bunu olduğu gibi iletecektir. Başlangıçta yürütülebilir dosyayı belirtmek yerine yalnızca programı çalıştırdıysanız... gdbİkili dosyayı daha sonra komutla ilişkilendirebilirsiniz. dosya:
(gdb) file memsim
Daha GDB'den çıkış sadece yaz quit veya kısaltması qProgram çalışıyorsa, GDB hata ayıklamayı sonlandırmak için onay isteyecektir.
Pratik örnek: Segmentasyon hatası tespiti
İş akışını anlamak için klasik bir örneğe bakalım. Bir sayı isteyen, 1 ile herhangi bir sayının toplamını hesaplayan, sonucu görüntüleyen ancak bellek hatası içeren bir C programı hayal edin:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *buf;
int sum_to_n(int num) {
int i, sum = 0;
for (i = 1; i <= num; i++)
sum += i;
return sum;
}
void printSum() {
char line;
printf("enter a number:\n");
fgets(line, 10, stdin);
if (line != NULL)
strtok(line, "\n");
sprintf(buf, "sum=%d", sum_to_n(atoi(line)));
printf("%s\n", buf);
}
int main() {
printSum();
return 0;
}
Ortada bariz bir gariplik var, ama olduğu gibi çalıştırırsanız, derleyip çalıştırmanız felaketi ortaya çıkaracaktır:
gcc -g -o crash crash.c
./crash
enter a number:
5
Segmentation fault
Sistem yalnızca bir tanesi hakkında uyarı veriyor. Geçersiz bellek erişimiHepsi bu kadar. Şimdi, programı GDB içinde çalıştırırsanız çok daha fazla ayrıntı görebilirsiniz. İkili dosyayı yükleyin ve çalıştırın:
gdb crash
(gdb) run
Starting program: ./crash
enter a number:
10
Bir hata oluştuğunda, GDB size ilgili sinyalle bildirimde bulunur:
Program received signal SIGSEGV, Segmentation fault.
0x0017fa24 in _IO_str_overflow_internal () from /lib/tls/libc.so.6
Sizi oraya götüren şeyin ne olduğunu öğrenmek için şu komutu kullanırsınız. geri izleme (o bt):
(gdb) backtrace
#0 0x0017fa24 in _IO_str_overflow_internal() from /lib/tls/libc.so.6
#1 0x0017e4a8 in _IO_default_xsputn_internal() from /lib/tls/libc.so.6
#2 0x001554e7 in vfprintf() from /lib/tls/libc.so.6
#3 0x001733dc in vsprintf() from /lib/tls/libc.so.6
#4 0x0015e03d in sprintf() from /lib/tls/libc.so.6
#5 0x08048487 in printSum() at crash.c:22
#6 0x080484b7 in main() at crash.c:28
İz, şunu gösteriyor ki main fonksiyonu printSum fonksiyonunu çağırdı, o da sprintf fonksiyonunu çağırdı.Oradan itibaren, bir dizi dahili libc fonksiyonu çökmeye yol açtı. Uygulamanın koduna dokunamayız. sprintfAncak 22. satırda hangi parametreleri geçirdiğimizi görebiliriz. crash.c.
Kesme noktaları, adım adım yürütme ve temel komutlar
Hata ayıklayıcının güzelliği, ihtiyaç duyduğunuz yerde yürütmeyi durdurabilme yeteneğindedir. Hata ayıklayıcıların amacı da budur. kırılma noktalarıBu komutlar, bir satırın yürütülmesinden hemen önce veya bir fonksiyona girildiğinde programı durdurur.
Önceki örnekte, çağrıdan hemen önce ne olduğunu görmek istiyoruz. sprintf22. satıra bir kesme noktası koyabiliriz. crash.c Doğrudan GDB'den:
(gdb) break crash.c:22
Breakpoint 1 at 0x804845b: file crash.c, line 22.
Programı yeniden çalıştırırsanız koşmakGDB size zaten çalıştığını bildirecek ve sıfırdan başlamak isteyip istemediğinizi soracaktır. Evet deyin ve kırılma noktasına ulaşın:
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: ./crash
enter a number:
10
Breakpoint 1, printSum() at crash.c:22
22 sprintf(buf, "sum=%d", sum_to_n(atoi(line)));
Program orada durdurulduktan sonra, şu komutla değişkenleri inceleyebiliriz. baskı (o p):
(gdb) print line
$1 = "10\000\000\000\000\000\000…"
Okuduğumuz metin mantıklı görünüyor. Şimdi işaretçiye bakalım. buf:
(gdb) print buf
$2 = 0x0
Sorun şu: Taşınıyoruz... sprintf null işaretçi Hedef olarak, yani geçersiz bir adrese yazmaya çalışmak. Çözüm, bellek ayırmaktır. buf Ya da başlatılmamış bir işaretçi yerine yerel bir dizi kullanın.
GDB ayrıca şunlara da izin verir: satır satır yürüt komutlar sayesinde sonraki (N), adım (kum kadar (veya):
- sonraki (n): Sonraki satırı yürütür, ancak bir fonksiyon çağrısı varsa, içine girmeden hemen yürütür.
- adım(lar)Bu satır yürütülür ve eğer bir fonksiyon çağrılmışsa, o fonksiyonun ilk komutunu girer; bu, kendi fonksiyonlarınızı takip etmek için idealdir.
- (u)'ya kadar: Döngü içinde çok kullanışlıdır; döngüden çıkıp belirtilen satıra veya döngünün dışındaki bir sonraki satıra ulaşana kadar yürütmeye devam eder.
Örneğin, döngü satırına bir kesme noktası koyarsanız... sum_to_n ve sonra kullanırsınız n o uTüm turları manuel olarak tek tek incelemenize gerek kalmadan, akümülatörün nasıl geliştiğini görebilirsiniz:
(gdb) break crash.c:10
(gdb) run
Breakpoint 1, sum_to_n (num=50) at crash.c:10
10 for (i = 1; i <= num; i++)
(gdb) n
11 sum += i;
(gdb) n
10 for (i = 1; i <= num; i++)
(gdb) until 12
12 return sum;
Programın bir sonraki kesme noktasına kadar veya bitene kadar çalışmaya devam etmesini istediğinizde şunu kullanırsınız: devam etmek (o c):
(gdb) continue
Continuing.
Koşullu kesme noktaları ve kesme noktası yönetimi
Büyük döngüler veya çok sayıda yineleme içeren programlarda, her zaman "aynı yerde" durmak istemezsiniz. İşte bu noktada döngüler devreye girer. koşullu kesme noktalarıBunlar yalnızca mantıksal bir koşulun sağlanması durumunda etkinleşir.
Diyelim ki içeride durmak istiyorsunuz. sum_to_n yalnızca parametre num 50 olsun. Öncelikle istediğiniz satırda kesme noktası oluşturun ve ardından koşulu ekleyin:
(gdb) break crash.c:10
Breakpoint 1 at 0x8048441: file crash.c, line 10.
(gdb) condition 1 num == 50
Program yeniden başlatıldıktan sonra, GDB yalnızca şu durumlarda duracaktır: num vale 50 O çizgiye ulaşıldığında:
(gdb) run
Starting program: ./crash
enter a number:
50
Breakpoint 1, sum_to_n (num=50) at crash.c:10
10 for (i = 1; i <= num; i++)
Aktif kırılma noktalarını ve sayılarını kontrol etmek için şunu kullanabilirsiniz: bilgi kırılma noktalarıKesme noktaları çeşitli komutlarla değiştirilebilir:
- silmek: argüman belirtilmediğinde tüm kesme noktalarını siler; bir sayı ile kullanıldığında ise yalnızca belirtilen kesme noktasını siler (
delete 1). - açık: Bir fonksiyon veya satırla ilişkili kesme noktasını kaldırır (
clear main,clear 42...). - devre dışı bırak / etkinleştirBu özellik, bir kesme noktasını geçici olarak devre dışı bırakmanıza ve daha sonra yeniden etkinleştirmenize olanak tanır.
Klasik kırılma noktalarına ek olarak, şunlar da vardır: izleme noktalarıBelirli bir çizgide durmayan, ancak durduklarında değiştirir veya okur Bir değişkenin içeriği. Bunlar şu şekilde oluşturulur: watch variable (değişiklikler için) veya rwatch variable (okumalar için) ve aşağıdaki şekilde listelenmiştir: info watchKarmaşık bir yapı üzerindeki beklenmedik yazıları tespit etmek için çok kullanışlıdırlar.
Kod, değişkenler ve bellek hakkında daha fazla bilgi edinin.
Program durdurulmuş haldeyken, çoğunlukla kodda gezinecek ve değerlere bakacaksınız. GDB bunun için oldukça kullanışlı bir komut koleksiyonu sunuyor, bunlardan ilki şöyle: listeEkran üzerinde kaynak metnin parçalarını gösteren bir özellik.
En yaygın kullanım list Bu, bir satır numarası veya fonksiyonun etrafındaki birkaç satırı istiyor:
list 20: 20. satırın ortasına odaklanmış bazı çizgiler gösteriyor.list main: listelemeye baştan başlarmain.listBasitçe söylemek gerekirse: gösterilen son satırdan itibaren listelemeye devam eder.
Değerleri incelemek için, daha önce de gördüğümüz gibi... baskı Bu, yıldız komutudur, ancak basit değişkenlerle sınırlı değildir. Değerlendirme yapabilirsiniz. tam ifadelerTür dönüştürme işlemleri gerçekleştirebilir, yapı alanlarına erişebilir veya dizi elemanlarını görüntüleyebilirsiniz:
(gdb) print intermedio
$1 = 134513691
(gdb) print primero
$2 = 2654196
(gdb) print lista@25
Başlangıç değerleri atanmamış değişkenlere sahip bir program örneğinde, GDB size bunu hızlı bir şekilde doğrulama olanağı sağlar. Yerel bir değişkene başlangıç değeri atanmamıştır. ve içeriğinin anlamsız verilerden oluştuğunu açıklıyor. Bu da her çalıştırmanın neden farklı bir sayı yazdırdığını açıklıyor; bu durum, başlatılmamış otomatik belleğe güvenildiğinde tipiktir.
Ham bellek içeriğini tek yönde görüntülemeniz gerekiyorsa, bunları birleştirebilirsiniz. yazdır &değişken Bir adres almak ve ardından komutu kullanmak x (incelemek):
(gdb) print &num
$1 = (int *) 0xbffff580
(gdb) x 0xbffff580
0xbffff580: 0x00000064
Ayrıca ile tip GDB'den bir değişkenin veya ifadenin türünü isteyebilirsiniz; bu, C++'da karmaşık yapılar veya şablonlarla çalışırken türler konusunda kafanız karışırsa kullanışlıdır:
(gdb) ptype saldo_ptr
Bir diğer güçlü özellik ise şu yeteneğe sahip olmasıdır: Değişkenleri anlık olarak değiştir komutla set varÖrneğin, eğer bir işaretçi istiyorsanız... saldo_ptr Şunu işaret edeceğim: saldo Arınma süreci boyunca:
(gdb) set var saldo_ptr = &saldo
Bu noktadan itibaren, yürütme bu yeni değerle devam eder ve programı her seferinde yeniden derlemeden senaryoları test etmenize olanak tanır.
Yürütme ve çağrı yığınının hassas kontrolü
Büyük programlara girdiğinizde, sadece satır satır ilerlemek yeterli değildir; bilmeniz gerekir. Buraya kadar nasıl geldiniz? ve farklı çağrı bağlamları arasında geçiş yapın. GDB, yığını yönetmek ve farklı çerçeveler arasında gezinmek için çeşitli komutlar sunar.
Komut nerede (o geri izleme/bt```, geçerli fonksiyondan giriş noktasına kadar çağrı yığınını görüntüler. Her çerçeve, fonksiyonu, parametreleri ve dosya/satırı içerir. Bu çerçevelerde yukarı ve aşağı doğru gezinmek için ``` tuşlarını kullanabilirsiniz. up y aşağı Yerel değişkenleri farklı seviyelerde incelemek:
(gdb) where
#0 funcion_profunda() at modulo.c:120
#1 calcula() at core.c:45
#2 main() at main.c:30
Daha bir fonksiyondan hızlıca çıkış yapın Sonuna kadar adım adım gitmeden, işte komut. bitişBu, mevcut fonksiyonun geri kalan gövdesini yürütür ve çağrı noktasında yürütmeyi durdurarak sizi önceki kareye döndürür.
Eğer hata ayıklamanın doğrudan başlamasını istiyorsanız main Libc başlatma koduna ilk önce uğramaya gerek kalmadan, çok kullanışlı bir kısayol var: Ana Sayfayı BaşlatBu komut programı başlatır ve fonksiyonun tam başına geçici bir kesme noktası yerleştirir. main.
Son girilen komutu tekrarlamak için, yapmanız gereken tek şey şudur: ENTER tuşuna basın Boş bir satıra yazın. Bu, birden fazla öğeyi birbirine bağlarken çok kullanışlıdır. next o step takip etti.
GDB'de klavye kısayolları ve geçmiş yönetimi
GDB terminalden kullanıldığı için GNU Readline'ın satır düzenleme özelliklerinden yararlanır. Bu da, geniş bir yelpazede kod kullanabileceğiniz anlamına gelir. klavye kısayolları Komutları tek tek elle yazmak zorunda kalmadan, komutlar arasında gezinmeyi, komutları düzenlemeyi ve önceki komutları yeniden kullanmayı sağlar.
En kullanışlı kısayollar arasında şunlar yer almaktadır:
- CTRL+P / CTRL+NKomut geçmişinde geriye veya ileriye doğru gezinme.
- CTRL+A / CTRL+EGeçerli satırın başına veya sonuna atla.
- CTRL+B / CTRL+F: Bir karakteri sola veya sağa hareket ettir.
- ALT+F / ALT+B: Kelime kelime ileri veya geri hareket et.
- CTRL + Kİmlecin bulunduğu konumdan satır sonuna kadar olan kısmı keser ve bir arabelleğe kaydeder.
- CTRL + YKesilen son öğeyi imleç konumuna yapıştırın.
- CTRL+_ o CTRL+X CTRL+U: Satırda yapılan son düzenlemeyi geri alın (bunu birkaç kez tekrarlayabilirsiniz).
- CTRL + LÇıktı bozulmuşsa ekranı yenileyin.
- CTRL + CHata ayıklamasını yaptığınız programın yürütülmesini durdurun.
- CTRL+XATerminalde bölünmüş kaynak kod görünümünü etkinleştirmek veya devre dışı bırakmak için.
- CTRL+X 2: İkinci bir "pencere" açın (örneğin, assembler ile) ve görünümler arasında geçiş yapın.
Çabucak edinilen alışkanlıklardan biri de tarihe aşırı derecede güvenmektir. CTRL+P ve ENTER Komutları tekrarladığınızda, örneğin run, next o printve kullanın CTRL + R (Readline'dan miras alınan ters arama özelliği) Bir süre önce çalıştırdığınız bir komutu bulmak için kullanılır.
Günlük kullanım için diğer faydalı GDB komutları
Daha önce bahsedilenlerin dışında, her dakika kullanmasanız bile aklınızda bulundurmaya değer birkaç komut daha var çünkü Çok özel durumları çözüyorlar. zarif bir şekilde.
- yardım etDahili yardım özelliğini görüntüler;
helpSadece genel konuları öğretiyor vehelp comandoHer siparişin detaylarına girin. - bilgi alt komutlarla birlikte: örneğin,
info functionsProgram fonksiyonlarını listelemek için,info localsGeçerli karenin yerel değişkenlerini görüntülemek için, veyainfo breakpointsTüm kırılma noktalarını kontrol etmek için. - koşmak Argümanlarla: Normal konsolda olduğu gibi, parametreler ve yönlendirmeler geçirebilirsiniz:
run 2048 24 4orun >salida.txt. - açıkBelirtilen fonksiyon veya satırdaki kesme noktasını, dahili numarasını hatırlamaya gerek kalmadan kaldırır.
- devam etmek: Bir sonraki kesme noktasına veya programın sonuna kadar yürütmeye devam eder.
- çıkmakGDB oturumu sona eriyor; program hala çalışıyorsa onay isteyecektir.
Bu komut ve kısayol koleksiyonuyla, C veya C++'da neredeyse her türlü tipik hata ayıklama oturumunun üstesinden gelebilirsiniz: sembollerle derleme, GDB başlatma, İstenilen yerde dur, programın durumunu incele, değişkenleri değiştir Gerekirse, sorunun kaynağını bulana kadar devam edin.
GDB'yi adım adım yürütmeyi takip etmek, SIGSEGV'den sonra yığın izini kontrol etmek, izleme noktalarıyla değişkenleri izlemek ve tüm döngüleri atlamak için kullanmaya alıştıktan sonra... untilHata ayıklama, tahmin ve deneme yanılma yönteminden vazgeçerek çok daha hassas ve kontrollü bir incelemeye dönüşür; bu da kodun kendisini daha iyi anlamanızı sağlar.
Genel olarak bayt ve teknoloji dünyası hakkında tutkulu bir yazar. Bilgilerimi yazarak paylaşmayı seviyorum ve bu blogda da bunu yapacağım; size gadget'lar, yazılım, donanım, teknolojik trendler ve daha fazlasıyla ilgili en ilginç şeyleri göstereceğim. Amacım dijital dünyada basit ve eğlenceli bir şekilde gezinmenize yardımcı olmaktır.