gdb, Unix ailesinden olan bütün sistemlerde bulunan klasik bir hata ayıklayıcıdır.
gdb'nin 7 küsur sürümü D'yi de destekliyor. Ama daha öncekiler de belirli ölçüde kullanılabiliyor.
Benim ortamımdaki gdb şu:
'$ gdb --version
GNU gdb Fedora (6.8-37.el5)
..'
Bu güne kadar bilmediğim, D programlarının bizim için ilginç olan başlangıç noktasının _Dmain olmasıymış. C ve C++ programlarının giriş noktası main'dir. D'de ise main, D çalışma zamanı ortamının (D runtime) başlama noktasıymış. O yüzden bir C programı için vereceğimiz 'b main' komutu işimize yaramıyor. Biz, 'b _Dmain' demeliyiz.
Bu devirde bunların bir geliştirme ortamından yapılması gerekir ama yine de komut satırında çalışan bir gdb kullanımı göstereceğim:
- Aşağıdaki programı yazın ve deneme.d ismiyle kaydedin:
import std.stdio;
class Sınıf
{
bool b;
int i = 42;
void işlev()
{
if (b) {
writeln("merhaba");
}
}
}
void foo(int foo_parametresi)
{
auto nesne = new Sınıf;
nesne.işlev();
}
void bar(int bar_parametresi)
{
foo(bar_parametresi + 10);
}
void main()
{
bar(7);
}
Orada program akışı şu şekilde ilerliyor:
main() -> bar() -> foo() -> Sınıf.işlev()
- Programı gdb'nin okuyacağı 'debug' bilgisini de içersin diye -gc seçeneği ile derleyin:
'$ dmd deneme.d -w -wi -gc'
(Derleyici uyarılarını da almak için her zaman yaptığım gibi -w ve -wi de kullandım.)
- gdb'yi ismi 'deneme' olan programımızla başlatın:
'$ gdb deneme'
Bu noktadan sonra gdb'nin içindeyiz. Bazı komutlar vererek programın akışını gözlemleyebileceğiz:
b (break) Durak yerleştirir
run Programı bir sonraki durağa kadar işletir
p (print) Bir değişkenin değerini gösterir
n (next) Bir sonraki ifadeyi işletir
s (step) Çağırmak üzere olduğumuz işlevin içine ilerler
bt (back trace) Çağrı ağacının hangi dalında bulunduğumuzu gösterir; yani şu anda hangi işlevin çağırdığı hangi işlevin çağırdığı vs. vs. işlevin içindeyiz (Bu, ters sırada gösterilir: içinde bulunduğumuz en üstte, bizi çağıranlar altta)
continue Programı bir sonraki durağa kadar devam ettirir
quit gdb'den çıkar
Açıklamaları aşağıdaki gdb oturumunun sağ tarafına yazıyorum:
'
$ gdb deneme <--- konsolda yazdığım komut
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) b _Dmain <--- Programın başına durak yerleştir
Breakpoint 1 at 0x8076ec3: file deneme.d, line 27.
(gdb) run <--- Programı durağa kadar işlet
Starting program: /home/acehreli/deneme/d/deneme
[Thread debugging using libthread_db enabled]
[New Thread 0x3f4b50 (LWP 9767)]
Breakpoint 1, D main () at deneme.d:29 <--- Durduğumuz yeri bildiriyor
29 bar(7);
(gdb) s <--- Üzerinde durduğumuz işlevin içine gir
(En soldaki 29, programın hangi
satırında bulunduğumuzu bildiriyor)
deneme.bar (bar_parametresi=7) at deneme.d:24
24 foo(bar_parametresi + 10); <--- Şimdi buradayız
(gdb) s <--- foo'nun da içine gir
deneme.foo (foo_parametresi=17) at deneme.d:18
18 auto nesne = new Sınıf;
(gdb) bt <--- Şu anda çağrı ağacı ne durumda?
#0 deneme.foo (foo_parametresi=17) at deneme.d:18 <-- buradayız
#1 0x08076ebc in deneme.bar (bar_parametresi=7) at deneme.d:24 <-- bizi bu çağırmış
#2 0x08076ecd in D main () at deneme.d:29 <-- onu da bu çağırmış
(buradan öncesi bizi
ilgilendirmiyor)
#3 0x08079652 in _D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#4 0x080795ac in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#5 0x08079696 in _D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#6 0x080795ac in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#7 0x08079554 in main ()
(gdb) p foo_parametresi <--- foo_parametresi'nin değeri ne?
$1 = 17 <--- 17 imiş
(gdb) n <--- Bir sonraki satıra geç
19 nesne.işlev();
(gdb) s <--- nesne.işlev()'in içine gir
deneme.Sınıf.işlev (this=0x481e40) at deneme.d:10
10 if (b) {
(gdb) p *this <--- Bu nesnenin üyelerini göster
$2 = {b = false, i = 42} <--- Bütün üyeler ve değerleri
(gdb) bt <--- Şimdi nerelerden çağrılmışız?
#0 deneme.Sınıf.işlev (this=0x481e40) at deneme.d:10
#1 0x08076ea0 in deneme.foo (foo_parametresi=17) at deneme.d:19
#2 0x08076ebc in deneme.bar (bar_parametresi=7) at deneme.d:24
#3 0x08076ecd in D main () at deneme.d:29
#4 0x08079652 in _D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#5 0x080795ac in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#6 0x08079696 in _D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#7 0x080795ac in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#8 0x08079554 in main ()
(gdb) up <--- Bir önceki çağıranın düzeyine çıkalım
#1 0x08076ea0 in deneme.foo (foo_parametresi=17) at deneme.d:19
19 nesne.işlev();
(gdb) p nesne <--- nesne'nin değeri nedir?
$3 = (struct deneme.Sınıf *) 0x481e40 <--- Gördünüz mü? Sınıflar referans türü
olduklarından, nesne perde arkasında
aslında bir göstergeymiş. (Bunu, hem
türünde * bulunmasından, hem de
değerinin adrese benzemesinden
anlıyorum.)
(gdb) p *nesne <--- nesne'nin eriştirdiği ne?
$4 = {b = false, i = 42} <--- İşte bütün üyeleri
(gdb) continue <--- Programı işletmeye devam et
Continuing.
Program exited normally. <--- Başka durak yok; program bitti
(gdb) quit <--- gdb'den çık
'
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]