Forum: D Programlama Dili RSS
D programlarının işleyişini gdb ile incelemek
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: D programlarının işleyişini gdb ile incelemek
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:

1) 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()


2) 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.)


3) 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
yanikibo #2
Üye Eki 2010 tarihinden beri · 10 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Elinize sağlık Hocam,

Bayağı zamandır "debug writeln(...)" kullanarak hata ayıklıyordum :)
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
O da olur. Ben de hâlâ C ve C++ programlarında benzer satırlar kullanırım ama sonra silmeyi unutmamaya çalışırım. :)

Ali
canalpay (Moderatör) #4
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
O da olur. Ben de hâlâ C ve C++ programlarında benzerMetin  satırlar kullanırım ama sonra silmeyi unutmamaya çalışırım. :)

Silmek zararlı olmaz mı? Eğer debug kullanıyorsak orada hata oluşturabilme riskine sahip olduğunu düşündürmez mi bize? Eğer öyleyse her an denetlemek daha doğru olmaz mı?
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
(C ve C++'dan konuşuyoruz.)

Doğru. Bazı grupların DEBUGLOG gibi makroları oluyor, kodun içine serpiştiriyorlar:

DEBUGLOG("foo()'ya girildi");
// ...
DEBUGLOG("foo() icinde sayac: %d", sayac);
// ...
DEBUGLOG("foo()'dan cikildi");

Başka bir yerdeki bir değeri değiştirerek o mesajları etkinleştiriyorlar veya susturuyorlar. Ben ise aynı amaçla printf satırları yerleştiriyorum:

printf("foo()'ya girildi");
// ...
printf("foo() icinde sayac: %d", sayac);
// ...
printf("foo()'dan cikildi");

Benim onları susturma düzeneğim olmadığı için ve bir daha da işime yaramayacaklarını düşündüğüm için onları siliyorum.

Benimki tembellik veya ileriyi görmemek gibi düşünülebilir; çünkü ileride de hatala ayıklarken işime yarayabilirler. Ama DEBUGLOG gibi makroların sakıncaları da var:

- kodu kalabalıklaştırıyorlar

- o mesajlar aktifleştirilince her taraftakiler de etkinleşiyor ve kalabalık mesajlar arasında işime yarayanı bulmak zor oluyor (aslında bazen printf ile ekrana yazmıyorum, fprintf kullanarak bir dosyaya yazıyorum)

Herkes kullanışlı bulduğu yönteme devam etsin... :)

Ali
zafer #6
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
zafer@debian:~/DProjeler/debug$ gdb deneme
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 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 "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zafer/DProjeler/debug/deneme...done.
(gdb) b _Dmain
Breakpoint 1 at 0x8089f93: file deneme.d, line 29.
(gdb) run
Starting program: /home/zafer/DProjeler/debug/deneme
[Thread debugging using libthread_db enabled]

Breakpoint 1, _Dmain () at deneme.d:29
29        bar(7);
(gdb) s
_D6deneme3barFiZv (bar_parametresi=7) at deneme.d:24
24        foo(bar_parametresi + 10);
(gdb) s
_D6deneme3fooFiZv (foo_parametresi=17) at deneme.d:18
18        auto nesne = new Sınıf;
(gdb) bt
#0  _D6deneme3fooFiZv (foo_parametresi=17) at deneme.d:18
#1  0x08089f8c in _D6deneme3barFiZv (bar_parametresi=7) at deneme.d:24
#2  0x08089f9d in _Dmain () at deneme.d:29
#3  0x0808caf0 in _D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#4  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#5  0x0808cb32 in _D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#6  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#7  0x0808c744 in main ()
(gdb) p foo_parametresi
$1 = 17
(gdb) n
19        nesne.işlev();
(gdb) s
_D6deneme7Sınıf6işlevMFZv (this=0xf7d41ff0) at deneme.d:10
10            if (b) {
(gdb) p *this
$2 = {b = false, i = 42}
(gdb) bt
#0  _D6deneme7Sınıf6işlevMFZv (this=0xf7d41ff0) at deneme.d:10
#1  0x08089f70 in _D6deneme3fooFiZv (foo_parametresi=17) at deneme.d:19
#2  0x08089f8c in _D6deneme3barFiZv (bar_parametresi=7) at deneme.d:24
#3  0x08089f9d in _Dmain () at deneme.d:29
#4  0x0808caf0 in _D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#5  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#6  0x0808cb32 in _D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#7  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#8  0x0808c744 in main ()
(gdb) up
#1  0x08089f70 in _D6deneme3fooFiZv (foo_parametresi=17) at deneme.d:19
19        nesne.işlev();
(gdb) p nesne
$3 = (struct deneme.Sınıf *) 0xf7d41ff0
(gdb) p *nesne
$4 = {b = false, i = 42}
(gdb) continoue
Undefined command: "continoue".  Try "help".
(gdb) continue
Continuing.

Program exited normally.
(gdb) quit
zafer@debian:~/DProjeler/debug$


Merhaba,
Programlar karmaşıklaşmaya başladıkça hata ayıklama olanaklarını kullanmak bazen can kurtarıcı oluyor. Konu ile araştırma yaparken bu konuya rastladım eline sağlık Ali çok güzel bir anlatım olmuş. Bence bu ders olarak biraz daha genişletilip kitabada eklenmeli, tuhaf olan bu konu çok kısa bırakılmış oysa bence çok değerli bir forum konusu olmuş.

Anladığım kadarıyla henüz D dilinde popüler dillerdeki gibi görsel bir hata ayıklama programı bulunmuyor, bizde komut satırından hata ayıklamaya devam edicez gibi popüler dillerdeki kolaylıklardan sonra biraz zahmetlli olacak gibi ama eğlenceli olacağına eminim :) gdb ile uzun süredir bakışır dururduk meğer tanışmak bugüne kısmetmiş. Bu arada anladığım kadarıyla gdb'nin biraz daha kullanıcı dostu görsel arayüzlü bir uygulamasıda geliştirilmiş ancak gdb'yi bilmeden iş çıkarmak zor gürünüyor. http://www.gnu.org/s/ddd/

Yukarıdaki konsol çıktısını konuda anlatılanlara göre yaptım ama bazı farklar var onları anlamadım mesela senin çıktı şöyle iken
(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 ()

Bendeki çıktının sonucu şöyle görünüyor
(gdb) bt
#0  _D6deneme3fooFiZv (foo_parametresi=17) at deneme.d:18
#1  0x08089f8c in _D6deneme3barFiZv (bar_parametresi=7) at deneme.d:24
#2  0x08089f9d in _Dmain () at deneme.d:29
#3  0x0808caf0 in _D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#4  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#5  0x0808cb32 in _D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#6  0x0808c795 in _D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#7  0x0808c744 in main ()

Mesela burada sende "deneme.foo" yazarken bendeki çıktıda "_D6deneme3fooFiZv" gibi karışık bişey yazıyor. Senin çıktıyı okumak çok daha kolay bende neden böyle oldu hata mı yaptım?

Aklıma takılan diğer birkaç konu;
    1. Kesme noktası (break point) yerleştireceğimiz noktaları nasıl seçiyouz? Örneğin 25 gibi satır numarası verebilir miyim?
    2. run ile ayiklamaya başladıktan sonra kesme noktası koyabilir miyiz?
    3. bt komutu ile aldığımız listeyi biraz daha açıklar mısın?
    4. *this standart bir kullanım mıdır, yoksa sınıfı işaret ettiği için mi öyle kullandık. sınıfın isminide verebilir miyiz?
    5. Girilen metoda ait kodun tamamını bir seferde görme şansımız var mı?
https://github.com/zafer06 - depo
acehreli (Moderatör) #7
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bence bu ders olarak biraz daha genişletilip kitabada eklenmeli

Yeni ders konusu belli oldu! ;)

bu konu çok kısa bırakılmış

Ben C ve C++ için de gdb'nin bundan fazlasını kullanmıyorum. :D

Anladığım kadarıyla henüz D dilinde popüler dillerdeki gibi görsel bir hata ayıklama programı bulunmuyor

Öte yandan, forum konusu açıldıktan sonra benim sistemim değişmiş ve "GNU gdb (GDB) 7.2-ubuntu" kullanmaya başlamışım. Emacs içinde çalıştırmak artık C ve C++'tan alışık olduğum gibi: bir pencerede gdb komutlarını verirken diğer pencerede kaynak kodun satırlarını görüyorum! Nefis, nefis! :)

görsel arayüzlü bir uygulamasıda geliştirilmiş ancak gdb'yi bilmeden iş çıkarmak zor gürünüyor. http://www.gnu.org/s/ddd/

Ondan da hep haberim vardı. Çok güzel bir araç ama benim deneyimlerime göre gdb'nin bu kadarı gerçekten yetiyor.

senin çıktı şöyle iken ... Bendeki çıktının sonucu şöyle görünüyor

Benimki artık daha da değişmiş. Üstelik -m32 ve -m64 seçenekleriyle derlemek farklı sonuçlar doğuruyor. -m64 durumunda işlevlere girerken parametre listesinde de fazladan duruluyor.

(gdb) bt
#0  deneme.Sınıf.işlev (this=0x7fffffffe170) at deneme.d:50738
#1  0x0000000000445460 in deneme.foo (foo_parametresi=17) at deneme.d:50749
#2  0x000000000044547a in deneme.bar (bar_parametresi=7) at deneme.d:50754
#3  0x000000000044548a in D main () at deneme.d:50759
#4  0x0000000000448e7f in rt.dmain2.main() ()
#5  0x000000000069a010 in ?? ()
#6  0x0000000000000000 in ?? ()


bendeki çıktıda "_D6deneme3fooFiZv" gibi karışık bişey yazıyor

gdb'nin sürümüne, işletim sistemine, ve -m seçeneğine göre değişebilir. Bu kadarına da şükür. :)

    1. Kesme noktası (break point) yerleştireceğimiz noktaları nasıl seçiyouz? Örneğin 25 gibi satır numarası verebilir miyim?

Evet. gdb'de 'help' komutu var ama hem kolay anlaşılamayabiliyor hem de tam bilgi vermeyebiliyor. :-/ Örneğin 'help b'.

    2. run ile ayiklamaya başladıktan sonra kesme noktası koyabilir miyiz?

Her zaman koyulabilir. 'd <numara>' da o numaralı kesme noktasını siler.

    3. bt komutu ile aldığımız listeyi biraz daha açıklar mısın?

Program işlevlerin içlerine dallandıkça nerede olduğunu hatırlamak için progrom yığıtını (program stack) kullanır. Yukarıdaki çıktıdan anlaşıldığına göre deneme.Sınıf.işlev'den çıkınca deneme.foo'ya dönülecekmiş, ondan çıkınca deneme.bar'a dönülecekmiş, vs. (ters sırada).

#0 program yığıtında 0 numaralı stack frame olduğunu belirtiyor.

0x0000000000445460 gibi değerler işlevlerin bellekteki başlangıç adreslerini gösteriyor.

Sağ tarafta da kaynak kodun neresinde bulunduğumuz belli.

    4. *this standart bir kullanım mıdır, yoksa sınıfı işaret ettiği için mi öyle kullandık. sınıfın isminide verebilir miyiz?

this, "şu anda geçerli olan nesneyi gösteren gösterge" anlamına geliyor. O yüzden de *this "bu nesne" demek. deneme.Sınıf.işlev() çağrısı hangi nesne üzerinde ise onun hakkında bilgi ediniyoruz. foo'nun sonuna şu satırları eklersen işlev()'in ikinci çağrısında ikinci nesneyi görürsün:

    auto nesne2 = new Sınıf;
    nesne2.i = 11111;
    nesne2.işlev();

    5. Girilen metoda ait kodun tamamını bir seferde görme şansımız var mı?

Emacs gibi süper ;) araçlar zaten bir pencerede de kodu ilerletiyorlar ama gdb'nin 'list' komutuna bakabilirsin.

Ali
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Aklıma bir kullanım daha geldi: set komutu ile değişkenlerin değeri programın çalışması sırasında değiştirilebilir. Örneğin işlev() içindeyken b'nin değeri false olduğu için writeln satırı işletilmiyor.

Tam if (b) satırı üzerindeyken b'nin değeri true yapılabilir (gdb 'true'dan anlamadığı için 1 değerini kullanmak gerekiyor):

(gdb) p this.b            <--- Tam 'if (b) {' satırındayken
$5 = false                <--- this.b'nin değeri false'muş
(gdb) set this.b=1        <--- 1 (yani true) yapıyoruz
(gdb) n                   <--- artık koşulun içine giriyor
(gdb) n                   <--- writeln'ı işletiyor
merhaba                   <--- ve kanıtı :)


Ali
zafer #9
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
bu konu çok kısa bırakılmış
Ben C ve C++ için de gdb'nin bundan fazlasını kullanmıyorum. :D

Neticede bakıldığında çok fazla detayı yok zaten. Benim söylemek istediğim kavram olarak hata ayıklama üzerinde fazla durulmamış demekti. Bence hata ayıklama da önemli bir konu diye düşünüyorum.

gdb'nin sürümüne, işletim sistemine, ve -m seçeneğine göre değişebilir. Bu kadarına da şükür. :)

Eğer böyle diyorsan daha fazla karıştırmıyorum ve böyle kullanmaya çalışıyorum  :-D
https://github.com/zafer06 - depo
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-19, 00:50:38 (UTC -08:00)