[LinuxFocus-icon]
<--  | Ana Sayfa  | Erişimdüzeni  | İçindekiler  | Arama

Duyumlar | Belgelikler | Bağlantılar | LF Nedir
Bu makalenin farklı dillerde bulunduğu adresler: English  Deutsch  Francais  Russian  Turkce  

[Photo of the Author]
Guido Socher (homepage)

Yazar hakkında:

Guido, sorunları araştırma fırsatı tanıdıkları için Linux gibi açık kaynak kodlu sistemlerden hoşlanmaktadır. Eğer, zaman ayırabilirseniz, sorunların ana kaynağını bulmanız olasıdır.



Türkçe'ye çeviri:
Erdal Mutlu <erdal(at)linuxfocus.org>

İçerik:

 

Bu neden çalışmıyor? Linux uygulamalarındaki hatalar nasıl belirlenebilir ve düzeltilebilir?

bug

Özet:

Herkes Linux altında çalışan uygulamaların hatalarını kolayca belirlenebileceğinden ve düzeltilebileceğinden söz ediyor. Ne yazık ki, bunun nasıl yapıldığını anlatan belgeler bulmak çok zor. Bu yazıda, bir uygulamanın aslında nasıl çalıştığını öğrenmeden, uygulamada oluşan hataları bulmayı öğreneceksiniz.

_________________ _________________ _________________

 

Giriş

Herşey düzgün ve uygulamadan beklendiği gibi çalıştığı sürece, bir uygulamanın açık mı yoksa kapalı kaynak koda sahip mi olduğu kullanıcı açısında hiç önemli değildir. Ancak, birşeyler artık çalışmamaya başladığında durum değişmektedir ve herkes er veya geç böyle bir durumla karşı karşıya kalamaktadır.

Kaynak kodu kapalı olan sistemlerde bir sorun ortaya çıktığında, yapabilecekleriniz genelde aşağıdaki iki seçenekle sınırlıdır:

Linux altında bu seçeneklere sahipsiniz tabii, ama bunların yanısıra sorunun nedenini araştırmaya da başlayabilirsiniz. Burada, uygulamayı yazanın bir başkası olması ve uygulamanın nasıl çalıştığı hakkında bir fikrinizin olmayışı gibi, bazı engeller vardır.

Bu engellere karşın, programın tüm kaynak kodunu okumadan ve hasıl çalıştığını öğrenmeden önce, yapabileceğiniz şeyler vardır.  

Çetele dosyaları

Herkesçe bilinen ve yapabileceğiniz şey, /var/log/ dizinindeki çetele dosyalarına bakmaktır. Oradaki dosyalarda, dosya isimleriyle içerikleri yapılandırılabilir. Genelde bakmanız gerekn dosya /var/log/messages dir. Çok fazla çetele bilgisi oluşturan uygulamaların kendi çetele dosyaları olabilir (/var/log/httpd/ /var/log/exim vs.).
Çoğu Linux dağıtımında sistem çetele verilerinin saklanmasından syslog servisi sorumludur ve bu /etc/syslog.conf yapılandırma dosyası tarafından denetlenebilir. Yapılandırma dosyasının yapısı "man syslog.conf"'da belgelendirilmiştir.

Uygulamasında çetele verileri yaratmak isteyen bir yazılımcı varsa, programına syslog satırları eklemesi yeterlidir. syslog, printf gibi çalışmaktadır, farkı sistem çetele dosyasına yazmasıdır. Çetelesi tutulacak iletinin yanı sıra fonksiyona, önceliği(priority) ve olanağı(facility) belirtmek gerekiyor:
       #include 

       void openlog(const char *ident, int option, int facility);
       void syslog(int priority, const char *format, ...);
       void closelog(void);

facility (olanak) iletiyi gönderenin hangi türden bir uygulama olduğunu belirler.
priority (öncelik) iletinin önemini belirtmektedir.
priority (öncelik) için olası değerler şunlardır:

       LOG_EMERG
       LOG_ALERT
       LOG_CRIT
       LOG_ERR
       LOG_WARNING
       LOG_NOTICE
       LOG_INFO
       LOG_DEBUG
C programlama dilinde yazılan her program sistem çetele dosyasına yazabilir. Diğer programlama dillerin de kendi olanakları vardır. Kabuk betikleri bile çetele tutabilir:
logger -p err "Bu yazı /var/log/messages dosyasına yazılacaktır."
syslog'un standart yapılandırma dosyasında (/etc/syslog.conf) başka yapılandırmaların yanısıra, aşağıdakine benzer bir satır olması gerekir:
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages.
*.info;mail.none;authpriv.none     /var/log/messages
"*.info" öncelik seviyesi LOG_INFO veya daha yüksek olan herşeyi çetele dosyasına yazacaktır. Daha fazla bilgi görmek isterseniz, bunu "*.debug" yapıp syslog'u yeniden başlatabilirsiniz (/etc/init.d/syslog restart).

Bir uygulamada hata aramanın adımları aşağıdaki gibi olmalıdır:
1) tail -f /var/log/messages komutunu çalıştırın ve başka bir
kabuktan hatalı uygulamayı başlatın. Belkide daha şimdiden yanlış giden şeyler
hakkında bilgi elde edebilrsiniz.

2) Eğer, 1. adım yeterli olmazsa, /etc/syslog.conf'daki *.info yu
*.debug olarak değiştirin ve "/etc/init.d/syslog restart" komutuyla
syslog servisini yeniden başlatıp ve 1. adıma dönün.
Bu yöntemin eksiği, yazılımcının kaynak kodunda ne kadar denetim yaptığına ve bunları çetele dosyasına gönderip göndermemesine olmasıdır. Eğer, önemli yerlere syslog fonksiyonunu yereştirmemişse, hiçbir şey göremeyebilirsiniz. Başka bir deyişle, sorunları belirleyebilmenin şartı, yazılımcının bazı yerlerde sorunların çıkabileceğini öngörmüş olmasıdır.  

strace

Linux altında çalışan bir uygulama 3 tür fonksiyon çağırabilir:
  1. Kendi kodu içerisindeki bir fonksiyonu.
  2. Kütüphane fonksiyonlarını.
  3. Sistem çağrılarını.
Kütüphane fonksiyonları, uygulamanın kendi fonksiyonlarına benzemektedir, tek farkları başka bir paket içerisinde bulunmalarıdır. Sistem çağrıları ise, her ne kadar fonksiyonlar gibi gözükseler de, çekirdekle haberleşen bir yapıları vardır. Ekrana yazmak, dosyadan okumak veya dosyaya yazmak, klavyeden gelen girişleri okumak, ağ üzerinden ileti göndermek gibi, bilgisayarınızın donanımlarıyla etkileşimde bulunma sırasında uygulamalar çekirdekle konuşmaktadır.

Bu sistem çağrıların arasına girilebilir, böylece uygulama ile çekirdek arasındaki haberleşme takip edilebilir.

Yapılandırma dosyasını bulamamak veya bir dizine yazı yazmak için yeterli erişim haklarına sahip olmamak, bir uygulamanın düzgün çalışmamasının sıkça rastlanan nedenlerdir. Bu sorunlar strace ile kolayca belirlenebilir. Bu durumda ilgili sistem çağrısının adı 'open' olacaktır.

strace'i aşağıdaki gibi kullanabilirsiniz::
strace your_application
İşte bir örnek:
# strace /usr/sbin/uucico
execve("/usr/sbin/uucico", ["/usr/sbin/uucico", "-S", "uucpssh", "-X", "11"],
       [/* 36 vars */]) = 0
uname({sys="Linux", node="brain", ...}) = 0
brk(0)                                 = 0x8085e34
mmap2(NULL, 4096, PROT_READ|PROT_WRITE,
     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000
open("/etc/ld.so.preload", O_RDONLY)  = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=70865, ...}) = 0
mmap2(NULL, 70865, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000
close(3)                              = 0
open("/lib/libnsl.so.1", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300;\0"..., 1024)
     = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=89509, ...}) = 0
mmap2(NULL, 84768, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40027000
mprotect(0x40039000, 11040, PROT_NONE)  = 0
mmap2(0x40039000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11)
     = 0x40039000
mmap2(0x4003a000, 6944, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) =
     0x4003a000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`X\1\000"..., 1024)
       = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1465426, ...}) = 0
mmap2(NULL, 1230884, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4003c000
mprotect(0x40163000, 22564, PROT_NONE)  = 0
mmap2(0x40163000, 12288, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_FIXED, 3, 0x126) = 0x40163000
mmap2(0x40166000, 10276, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40166000
close(3)                                = 0
munmap(0x40015000, 70865)               = 0
brk(0)                                  = 0x8085e34
brk(0x8086e34)                          = 0x8086e34
brk(0)                                  = 0x8086e34
brk(0x8087000)                          = 0x8087000
open("/usr/conf/uucp/config", O_RDONLY) = -1 ENOENT (No such file or directory)
rt_sigaction(SIGINT, NULL, {SIG_DFL}, 8) = 0
rt_sigaction(SIGINT, {0x806a700, [],
             SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0
rt_sigaction(SIGHUP, NULL, {SIG_DFL}, 8) = 0
rt_sigaction(SIGHUP, {0x806a700, [],
             SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0
rt_sigaction(SIGQUIT, NULL, {SIG_DFL}, 8) = 0
rt_sigaction(SIGQUIT, {0x806a700, [],
             SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL}, 8) = 0
rt_sigaction(SIGTERM, {0x806a700, [],
             SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0
rt_sigaction(SIGPIPE, NULL, {SIG_DFL}, 8) = 0
rt_sigaction(SIGPIPE, {0x806a700, [],
             SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0
getpid()                                = 1605
getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0
close(3)                                = -1 EBADF (Bad file descriptor)
close(4)                                = -1 EBADF (Bad file descriptor)
close(5)                                = -1 EBADF (Bad file descriptor)
close(6)                                = -1 EBADF (Bad file descriptor)
close(7)                                = -1 EBADF (Bad file descriptor)
close(8)                                = -1 EBADF (Bad file descriptor)
close(9)                                = -1 EBADF (Bad file descriptor)
fcntl64(0, F_GETFD)                     = 0
fcntl64(1, F_GETFD)                     = 0
fcntl64(2, F_GETFD)                     = 0
uname({sys="Linux", node="brain", ...}) = 0
umask(0)                                = 022
socket(PF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sa_family=AF_UNIX,
    path="/var/run/.nscd_socket"}, 110) = -1 ENOENT (No such file or directory)
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY)    = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=499, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000
read(3, "# /etc/nsswitch.conf:\n# $Header:"..., 4096) = 499
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x40015000, 4096)                = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=70865, ...}) = 0
mmap2(NULL, 70865, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000
close(3)                                = 0
open("/lib/libnss_compat.so.2", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\25"..., 1024)
     = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=50250, ...}) = 0
mmap2(NULL, 46120, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40169000
mprotect(0x40174000, 1064, PROT_NONE)   = 0
mmap2(0x40174000, 4096, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_FIXED, 3, 0xa) = 0x40174000
close(3)                                = 0
munmap(0x40015000, 70865)               = 0
uname({sys="Linux", node="brain", ...}) = 0
brk(0)                                  = 0x8087000
brk(0x8088000)                          = 0x8088000
open("/etc/passwd", O_RDONLY)           = 3
fcntl64(3, F_GETFD)                     = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=1864, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000
_llseek(3, 0, [0], SEEK_CUR)            = 0
read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1864
close(3)                                = 0
munmap(0x40015000, 4096)                = 0
getuid32()                              = 10
geteuid32()                             = 10
chdir("/var/spool/uucp")                = 0
open("/usr/conf/uucp/sys", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/var/log/uucp/Debug", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0600) = 3
fcntl64(3, F_GETFD)                     = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
fcntl64(3, F_GETFL)                     = 0x401 (flags O_WRONLY|O_APPEND)
fstat64(3, {st_mode=S_IFREG|0600, st_size=296, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE,
     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000
_llseek(3, 0, [0], SEEK_CUR)            = 0
open("/var/log/uucp/Log", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0644) = 4
fcntl64(4, F_GETFD)                     = 0
fcntl64(4, F_SETFD, FD_CLOEXEC)         = 0
fcntl64(4, F_GETFL)                     = 0x401 (flags O_WRONLY|O_APPEND)
Burada ne görüyoruz? İsterseniz aşağıdaki satırlara bir göz atalım:
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)   = 3
Elde edilen çıktıya bir bakalım. Program ilk önce /etc/ld.so.preload dosyasını okumaya çalışıyor ve başarısız oluyor, daha sonra /etc/ld.so.cache dosyasını okumaktadır. Burada başarılı olmakta ve 3 nolu dosya tanımlayıcısını elde etmektedir. /etc/ld.so.preload dosyasını okuyamaması tam olarak bir hata anlamına gelmeyebilir, çünkü belkide program varsa ilk önce bu dosyayı okumak istemiştir. Başka bir deyişle, bir dosyayı okuyamamak, mutlaka hata anlamına gelmeyebilir. Herşey programın tasarlanma şekline bağlıdır. strace çıktısındaki tüm open sistem çağrılarına bir göz atalım:
open("/usr/conf/uucp/config", O_RDONLY)= -1 ENOENT (No such file or directory)
open("/etc/nsswitch.conf", O_RDONLY)   = 3
open("/etc/ld.so.cache", O_RDONLY)     = 3
open("/lib/libnss_compat.so.2", O_RDONLY) = 3
open("/etc/passwd", O_RDONLY)          = 3
open("/usr/conf/uucp/sys", O_RDONLY)   = -1 ENOENT (No such file or directory)
open("/var/log/uucp/Debug", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0600) = 3
open("/var/log/uucp/Log", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0644) = 4
open("/etc/ld.so.preload", O_RDONLY)   = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)     = 3
Şimdi program /usr/conf/uucp/config dosyasını okumaya çalışıyor. Ooo! Ama bu çok garip benim dosyam /etc/uucp/config dir! Ve /etc/uucp/config dosyasını açmak isteyen hiçbir satır çıktıda görünmüyor. Hata bu olmalı işte. Herhalde yapılandırma dosyasının yeri, programın derlenmesi sırasında yanlış belirtildi.

Gördüğünüz gibi strace programı çok faydalı olabiliyor. Tek sorun, strace'in çıktısını tam olarak anlayabilmek için C programlama bilgisi gerektirmesidir, ama genelde sizin bu kadar derine inmeniz gerekmeyecektir.  

gdb ve core dosyaları

Bazen öyle oluyor ki, program 'Segmentation fault (core dumped)' iletisini görüntüleyerek aniden çöküyor. Bunun anlamı, bir programlama hatasından dolayı program, ayırttığının ötesinde bir bellek alanına yazmaya çalışmasıdır. Bu özellikle, program birkaç byte fazla yazmaya kalkıştığında ve sadece arasıra ortaya çıkan bir olay olabilir. Bunun nedeni, bellek ayırtma işleminin parça parça olması ve bazen rastlantı eseri fazladan gelen birkaç byte için yer kalıyor olmasıdır, yoksa böyle bir durum önceden kestirilmesi güç olaylara yol açabilir.

'Segmentation fault' hatası alındığında bulunulan dizinde (Genelde bu sizin ev dizininiz oluyor.), bir core (Programın bellek kullanım durumunu içeren ve bir hata ayıklayıcısının (debugger) anlayacağı biçimdeki bir dosya.) dosyası oluşmaktadır. core dosyası, hatanın oluştuğu andaki programın bellek kullanımının bir çıktısıdır. Bazı kabuk ortamları core dosyaların oluşturulup oluşturulmayacağını denetleyen olanaklar içermektedir. bash kabuğu kullanıldığında sözgelimi, benimsenmiş değer olarak core dosyaları oluşturulması iptal edilmiştir. Bu dosyaların oluşturulmasını istiyorsanız, aşağıdaki komutu çalıştırmanız gerekir:
# ulimit -c unlimited

# ./lshref -i index.html,index.htm test.html
Segmentation fault (core dumped)
Exit 139
Oluşan core dosyası, gdb hata ayıklayıcısı kullanılarak sorunun neden kaynaklandığı araştırması yapılabilir. gdb'yi çalıştırmadan önce, doğru core dosyasına baktığınızı denetlemede yarar vardır:
# file core.16897
core.16897: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style,
from 'lshref'
Tamam, bozuk olan program lshref dir ve onu şimdi gdb'ye yükleyebiliriz. gdb'yi bir core dosyasını incelemek için çalıştırmak istediğinizde, core dosyasının adıyla birlikte, bu dosyanın oluşmasına neden olan programı da belirtmeniz gerekmektedir.
# gdb ./lshref core.23061 
GNU gdb Linux (5.2.1-4)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
Core was generated by `./lshref -i index.html,index.htm test.html'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x40095e9d in strcpy () from /lib/libc.so.6
(gdb)

Şimdi artık programın strcpy fonksiyonunu kullanırken çöktüğünü biliyoruz. Ancak, program içerisinde strcpy birden fazla yerde kullanılıyor olabilir.

Genel olarak bu durumda, programın hangi yerinde hata oluştuğunu belirlemek için iki olasılık vardır:
  1. Programı hata ayıklama seçeneği ile (gcc için -g) yeniden derlemek.
  2. gdb'de yığıt izlemesi yapmak.
Bizim durumuzdaki sorun, strcpy'nin bir kütüphane fonksiyonu olması ve libc kütüphanesi dahil tüm kodu yeniden derlesek bile, en fazla C kütüphanesinin belli bir satırında başarısız olunduğunu elde edebileceğiz.

Bize gerekli olan ise, yığıtı inceleyip, sorun oluşmadan hemen önce hangi fonksiyonun strcpy'yi çağırdığını belirlemektir. gdb'de böyle bir şeyin yapılmasına olanak veren komutun adı 'backtrace' dir. Ancak bu, core dosyası kullanmamaktadır. Dolayısıyla, hatayı programı gdb içerisinde oluşturacak şekilde yeniden oluşturmanız gerekir:
gdb ./lshref core.23061
GNU gdb Linux (5.2.1-4)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
Core was generated by `./lshref -i index.html,index.htm test.html'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x40095e9d in strcpy () from /lib/libc.so.6
(gdb) backtrace
#0  0x40095e9d in strcpy () from /lib/libc.so.6
Cannot access memory at address 0xbfffeb38
(gdb) run ./lshref -i index.html,index.htm test.html
Starting program: /home/guido/lshref ./lshref -i index.html,index.htm test.html

Program received signal SIGSEGV, Segmentation fault.
0x40095e9d in strcpy () from /lib/libc.so.6
(gdb) backtrace
#0  0x40095e9d in strcpy () from /lib/libc.so.6
#1  0x08048d09 in string_to_list ()
#2  0x080494c8 in main ()
#3  0x400374ed in __libc_start_main () from /lib/libc.so.6
(gdb)

Şimdi görüyoruz ki, sorun yarat strcpy fonksiyonunu string_to_list() fonksiyonu, onu da main() çağırmıştır. string_to_list() fonksiyonuna bir bakalım:
char **string_to_list(char *string){
        char *dat;
        char *chptr;
        char **array;
        int i=0;

        dat=(char *)malloc(strlen(string))+5000;
        array=(char **)malloc(sizeof(char *)*51);
        strcpy(dat,string);
malloc satırında bir yazım hatası var gibi gözüküyor. Aslında şöyle olmalıydı:
dat=(char *)malloc(strlen(string)+5000);

Gerekli değişikliği yapıyor, programı yeniden derliyor ve ... yaşasın programımız çalışıyor.

İsterseniz, hatanın kütüphane dosyasında değil de uygulamanın bir yerinde olduğu durumu ele alan bir örnek üzerinde duralım.

İşte örneğimiz:
#include 
#include 

int add(int *p,int a,int b)
{
  *p=a+b;
  return(*p);
}

int main(void)
{
  int i;
  int *p = 0;   /* a null pointer */
  printf("result is %d\n", add(p,2,3));
  return(0);
}
Programı derliyor:
gcc -Wall -g -o exmp exmp.c
ve çalıştırıyoruz ...
# ./exmp
Segmentation fault (core dumped)
Exit 139
gdb exmp core.5302
GNU gdb Linux (5.2.1-4)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
Core was generated by `./exmp'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2

#0  0x08048334 in add (p=Cannot access memory at address 0xbfffe020
) at exmp.c:6
6         *p=a+b;

gdb, hatanın 6. satırda ve 'p' işaretçisinin, erişim hakkı olmadığı bir bellek alanına erişmek isterken oluştuğunu söylemektedir.

Yükarıdaki programın ilgili yerine bakarark, sorunun p null işaretçisi (yani hiçbiryeri göstermeyen) olduğu ve ona veri yüklemek istenildiği hemen görülmektedir. Bu, kasıtlı hazırlanan bir örnek olduğundan, sorunu bulmak ve gidermek kolay oldu.  

Sonuç

Programın asıl çalışması hakkında pek fazla bilgi sahibi olmadan bile, programda oluşan hataları bulabileceğimizi gördük.

Ben sözgelimi, bir grafik programındaki bir tuşun yanlış yerde görüntülenmesi gibi işlevsel hataları kasıtlı olarak burada ele almadım. Bu gibi durumlarda, programın işleyişinin bilinmesi gerekmektedir. Doğal olarak, bunun için daha fazla zaman harcamak gerekir ve nasıl yapılacağına ilişkin kesin bir tarif de yoktur.

Ancak, burada gösterilen basit hata bulma yöntemleri birçok durumda kullanılabilir.

Mutlu sorun gidermeler!  

Bu yazı için görüş bildiriminde bulunabilirsiniz

Her yazı kendi görüş bildirim sayfasına sahiptir. Bu sayfaya yorumlarınızı yazabilir ve diğer okuyucuların yorumlarına bakabilirsiniz.
 talkback page 

<--, Bu sayının ana sayfasına gider

Görselyöre sayfalarının bakımı, LinuxFocus Editörleri tarafından yapılmaktadır
© Guido Socher, FDL
LinuxFocus.org
Çeviri bilgisi:
en --> -- : Guido Socher (homepage)
en --> tr: Erdal Mutlu <erdal(at)linuxfocus.org>

2004-07-02, generated by lfparser version 2.43