리눅스개발도구 II - 디버깅 - 1
Contents C 프로그래밍오류의사례 gdb 디버거 메모리디버깅 기타디버깅 시스템콜, 라이브러리호출디버깅 매크로, assert() 2 System Security Lab@Myongji Univ.
프로그래밍오류 (error) 오류의유형 구문오류 (syntax error) 의미오류 (semantic error) 정적의미오류 (static semantic error) 동적의미오류 (dynamic semantic error) 논리오류 (logic error) 3 System Security Lab@Myongji Univ.
Syntax error 정해진구문에맞지않는오류 컴파일러의컴파일단계에서발견됨 예 x@ = 10; 식별자규칙에맞지않음 (@ 와같은특수기호는식별자로사용할수없음 ) if( x!= 0 if 문의구문에맞지않음 ( 오른쪽괄호를 빠뜨림 ) x = a +* c; 수식의구문에맞지않음 (+ 와 * 사이에 피연산자를빠뜨림 ) x = a 문장의구문에맞지않음 ( 세미콜론을 빠뜨림 ) 4 System Security Lab@Myongji Univ.
Static semantic error 정해진의미에맞지않는오류중에서컴파일단계에서발견되는오류 예 비호환타입의변수간의연산 : 연산은같은데이터타입간에수행되어야한다. 어떤연산은묵시적타입변환을수행해주기도한다 선언되지않은변수의사용 : 변수는사용전에선언 ( 정의 ) 되어야한다 함수의인자개수나인자타입의불일치 5 System Security Lab@Myongji Univ.
Dynamic semantic error 정해진의미에맞지않는오류중에서실행시간에발견되는오류 예 배열에서인덱스가배열의범위를넘어감 포인터가잘못된주소를참조함 0 으로나누기 6 System Security Lab@Myongji Univ.
Logic error 프로그래머가원래의목적대로프로그램을작성하지않아서발생하는오류 예 반복문의조건검사식에서값을잘못주어서무한루프를야기함 7 System Security Lab@Myongji Univ.
예제프로그램 int gcd(int v#) syntax error ( 식별자가잘못됨 ) { int a = value syntax error ( 세미콜론을빠뜨림 ) int t; y = v; static semantic error (y가정의안됨 ) while (y >= 0) { t = y; y = a % y; dynamic semantic error (0으로나눔 ) a = t; } return y; logic error (t를반환해야함 ) } 8 System Security Lab@Myongji Univ.
오류의사례 = 와 == 비교연산자대신에대입연산자를사용하는경우 if ( x = y ) 다음반복문을살펴보고결과를분석해보자 While ( c = c == \t c == \n ) {. } - 대입연산자대신에비교연산자를사용하는경우 if ( fd == open( sample.txt, 0) < 0 ) 9 System Security Lab@Myongji Univ.
오류의사례 (cont.) & 와 &&, 와 비트연산자 (&, ) : 비트단위의연산 논리연산자 (&&, ) : 참거짓의논리연산 역참조연산자 (*) *p 값으로나누기를할때 y = x /*p; /* 는설명문의시작 y = x / *p; / 와 * 사이를띄움 : 올바름 10 System Security Lab@Myongji Univ.
오류의사례 (cont.) 8 진수상수 0 으로시작하는숫자는 8 진수 int x = 0195; 8 진수 195 와 문자는 로둘러싸고, 문자열은 로둘러싸야함 char *splash = / ; printf( \n ); / 로해야함 \n 로해야함 11 System Security Lab@Myongji Univ.
오류의사례 (cont.) 세미콜론 (;) if, switch, for, while 문뒤에는세미콜론을붙여서는안된다 if( a > max ) { max = a; } 세미콜론이없음 do-while 문위에는세미콜론을붙인다. do { i++; } while (i < 5); 세미콜론이있어야함 12 System Security Lab@Myongji Univ.
오류의사례 (cont.) 세미콜론 (;) (cont.) 함수뒤에는세미콜론을붙여서는안된다. main() { } 세미콜론이없음 struct, union 선언문뒤에는세미콜론을붙여야한다 struct record { int date; int time; }; 세미콜론이있음 13 System Security Lab@Myongji Univ.
오류의사례 (cont.) switch 문에서 break 사용 case 문에서 break 문을생략하면, 그다음 case 문에나오는문장을계속수행한다. color = 2; switch( color ) { case 1: printf( red ); case 2: printf( yellow ); case 3: printf( blue ); } yellow 가아닌 yellowblue 가출력됨 14 System Security Lab@Myongji Univ.
오류의사례 (cont.) if 문에서 dangling else else 는가장가까운 if 와연관된다 if( x == 0 ) if( y == 0) error(); else else는어떤 if에연관되는가? z = x + y; 15 System Security Lab@Myongji Univ.
오류의사례 (cont.) 배열크기와인덱스 배열크기가 n 일때, 인덱스는 0 부터 n-1 이다 int a[10], i; for( i = 0; i <= 10; ++i) a[i] = 0; a[10] 의메모리위치가 i 의위치와같을수있으며, 이때, a[10]=0 은 i = 0 을수행하는효과를가지게되어, for 문은무한루프를수행하게됨 16 System Security Lab@Myongji Univ.
오류의사례 (cont.) 단축연산 논리연산자는피연산자두개중에서, 앞에나오는피연산자만으로결과가결정되면뒤에나오는피연산자는평가하지않는다 if( a < 10 && count++ < limit ) { } a 가 10 보다작으면 && 다음의수식은연산하지않는다. 따라서, count 값이증가하지않는다. 17 System Security Lab@Myongji Univ.
오류의사례 (cont.) 증감연산자 (++, --) 증감연산자가다른수식과같이쓰일때는연산의우선순위가불확실하다 a = 0; while( a < n ) x[a] = y[a++]; 원래의목적은 y[a] 값을 x[a] 에대입하고, a 값을증가시키는것이다. 그런데, 컴파일러마다결과가다를수있으므로다음과같이확실하게하는것이좋다. x[a] = y[a]; a ++; 18 System Security Lab@Myongji Univ.
오류의사례 (cont.) Linked list 구조체를 typedef 를사용하여선언할때 typedef struct { char item; NODEPTR *next; } *NODEPTR; 컴파일에러 다음과같이해주면됨. typedef struct node { char item; struct node *next; } *NODEPTR; struct node { char item; struct node *next; } ; typedef struct node *NODEPTR; 19 System Security Lab@Myongji Univ.
오류의사례 (cont.) 메모리누수 (memory leak) 할당받은동적메모리를반환하지않아서발생하는문제 malloc() 으로할당한동적메모리를 free() 하지않을때방생 char *buf; buf = (char *) malloc(100); if( error ) { } return error; free(buf); free() 를호출하지않고바로 return 동적메모리를할당하여그주소를가진포인터를잘못해서지웠을때발생 20 System Security Lab@Myongji Univ.
오류의사례 (cont.) 메모리손상 (memory corruption) 사용중인메모리를잃어버렸을때발생하는문제 함수에서지역변수의주소를가진포인터를반환했을때발생 : 지역변수는스택에임시로생성되었다가함수가끝나면소멸됨 int *function() { int a; int *p = &a; return p; } 소멸될 a 의주소를반환함 21 System Security Lab@Myongji Univ.
오류의사례 (cont.) 메모리손상 (memory corruption) (cont.) 할당받은메모리의앞또는뒤에있는메모리의읽기또는쓰기 배열에서인덱스가배열의범위를넘었을때 ( 앞을참고 ) 초기화되지않는메모리의읽기또는쓰기 초기화되지않은포인터의사용 int *p; *p = 100; p를초기화하지않고사용함 반환된메모리의읽기또는쓰기 free() 된이후에계속사용할때발생 22 System Security Lab@Myongji Univ.
gdb 디버거 23
gdb 디버거 GNU 디버거로서, C, C++, Fortran 등여러프로그램을디버깅할수있다. gdb 를사용하여디버깅하려면, 컴파일할때 g 옵션을사용해야한다. gcc g o myprog myprog.c 이옵션은목적파일내부에디버깅정보를삽입한다. 디버깅섹션보기 : objdump s myprog 소스코드가컴파일할때의디렉토리에있어야 gdb 에서소스코드를볼수있다. 소스코드가있는디렉토리를재지정할수있음 (dir dirname) 24 System Security Lab@Myongji Univ.
gdb 디버거 gdb 디버거의동작 디버깅정보가포함된바이너리파일을실행 ptrace 시스템호출을이용하여프로세스의제어권확보 정지점설정, 명령어단위수행 프로세스의메모리, 레지스터내용을접근 임베디드시스템의경우, 타겟컴퓨터에는 gdbserver 라는매우작은프로그램을실행하고 (ARM 의경우약 50KB), 호스트 PC 에서는 gdb 를실행하면서타겟의 gdbserver 와시리얼 / 네트워크통신하는원격디버깅이가능함 25 System Security Lab@Myongji Univ.
gdb gdb 시작하기 gdb program gdb program core-file gdb program pid program : 디버그할프로그램명 core-file : 디버그할프로그램이실행되면서만든코어파일 pid : 실행중인프로세스의 pid 예 ) gdb qsort2 시작하면 (gdb) 라는프롬프트를보여주고사용자의명령어를기다린다. 26 System Security Lab@Myongji Univ.
gdb 코어파일을이용한디버깅 코어파일 : 프로세스가오류 ( 주로 segmentation fault) 로인해종료되는순간의프로세스의이미지파일로서 CPU 레지스터, 프로세스의코드및데이터, 스택등의정보가들어있다. 만약, 프로그램이비정상종료되어도코어파일이만들어지지않는다면, 시스템에지정되어있는코어파일의크기를늘려주어야한다 ( 기본값은 0) ulimit S c unlimited./myprog gdb myprog core.12963 프로그램이왜종료되었는지를보여주고, 종료된지점의소스코드를보여준다. 27 System Security Lab@Myongji Univ.
gdb 코어파일을이용한디버깅 : 실습 /* File: segfault.c */ #include <stdio.h> main() { int *a = NULL; *a = 0x01; return 0; } $ gdb g o segfault segfault.c $./segfault Segmentation fault (core dumped) $ ls core* core.6663 $ gdb segfault core.6663 (gdb) 28 System Security Lab@Myongji Univ.
gdb 실행중인프로세스의디버깅 실행중인프로세스가죽지는않았지만, 올바르게수행되지않는경우에디버깅할수있다 먼저프로세스의 PID 를알아내야한다 ps gdb 를실행하고 attach 명령을사용한다 gdb myprog ( 가정 : myprog 가수행중 ) (gdb) attach 21001 ( 가정 : myprog 의 PID 가 21001) 이제디버거명령을이용하여디버깅하면됨 디버깅이끝나면 detach 명령을사용하여프로세스를떼어낸다 (gdb) detach 29 System Security Lab@Myongji Univ.
gdb 도움말보기 : help gdb 끝내기 : quit (q) 30 System Security Lab@Myongji Univ.
/* File : myprog.c */ #include <stdio.h> struct book{ int page; int price; } c_prog = {300, 10000}; int global_value = 0; char *color[3] = { blue, white, red }; func1(int a) { return a % 2; } int main() { int i, local_value = 10; char *local_str = c programming ; struct book *ptr = &c_prog; for(i = 0; i < 4; i++) { printf( color[i]=%s\n, color[i] ); if( func1(i) ) { local_value = local_value / global_value; printf( local_value = %d\n, local_value); } } } return 0; 31
소스보기 : list 소스파일내용보기 list (l) [ 행번호 ] list [ 함수명 ] list [ 파일명 ]:[ 함수명 ] list - 이전행출력 % gdb qsort2 (gdb) list 13 void qsort2(); 14 void swap(); 15 16 main() 17 { 18. 19. (gdb) set listsize N : 출력되는행의수를 N 으로설정 info source : 소스코드정보를보여줌 32 System Security Lab@Myongji Univ.
소스보기 : list [ 실습 ] 함수 func1 의소스를출력하기위한명령어를쓰시오. 함수 main 의소스를출력하기위한명령어를쓰시오. 33 System Security Lab@Myongji Univ.
소스코드편집 : edit 소스코드편집하기 디폴트편집기는 ex 편집기를 vi 로설정하려면, export EDITOR=/bin/vi 를한후, gdb 를수행 edit [ 행번호 ] edit [ 파일이름 ]:[ 행번호 ] edit [ 함수명 ] 34 System Security Lab@Myongji Univ.
프로그램실행하기 : run 프로그램실행하기 : run (r) % gdb qsort2 (gdb) run b < inputfile > outfile Program exited with code 0. (gdb) (gdb) set args b (gdb) show args 프로그램의인자를지정하고수행할수있음 프로그램의인자를따로지정할때 (gdb) r 0x22c8 in march( ) at ref.c:16 16 H = *p; (gdb) backtrace 프로그램이비정상적으로정지되면제어권이 gdb 로돌아오고프로그램내용을보여준다. backtrace 명령어로스택을역추적 35 System Security Lab@Myongji Univ.
프로그램실행하기 명령어 step (s) next (n) continue (c) until (u) finish return [ 반환값 ] 의미 현재행을실행후정지. 함수호출일경우함수내부로진입 현재행을실행후정지. 함수호출일경우함수를실행후다음행으로감 다음정지점까지계속실행 for 문을빠져나가서다음정지점까지실행 현재함수의끝지점까지실행 현재함수의나머지부분을실행하지않고빠져나감 step instruction (si) 현재명령어를실행후정지. 함수호출일경우함수내부로진입 next instruction (ni) 현재명령어를실행후정지. 함수호출일경우함수를실행후다음행으로감 36 System Security Lab@Myongji Univ.
정지점 (breakpoint) 설정 : break 정지점설정 : break (b) 예 b func b 10 b file.c:func b file.c:10 b +2 b -2 b *0x123456 b 10 if val=0 의미함수 func의시작부분에정지점설정 10행에정지점설정파일 file.c의함수 func의시작에정지점설정파일 file.c의 10행에정지점설정현재행에서 2 행이후지점에정지점설정현재행에서 2 행이전지점에정지점설정주소 0x123456에정지점설정 10행에정지점설정. 단, val이 0일때작동 정지점은 1 부터시작하는고유번호를가지며, gbd 가종료할때까지유효함 37 System Security Lab@Myongji Univ.
정지점 (breakpoint) 해제 : clear 정지점해제 : clear (cl) 또는 delete (d) 예 cl func cl 10 d d 2 의미함수 func에설정된정지점해제 10행에설정된정지점해제모든정지점해제정지점 2번해제 정지점보기 : info breakpoints (b) 현재설정되어있는정지점목록을출력 정지점에부여된번호, 위치등을볼수있다 38 System Security Lab@Myongji Univ.
정지점활성 / 비활성 : enable/disable 정지점활성 / 비활성 : enable/disable 예 enable b 2 disable b 2 의미 정지점 2 번을활성화 정지점 2 번을비활성화 39 System Security Lab@Myongji Univ.
정지점 [ 실습 ] 1. 함수 main 의 for 문블록의첫문장에서정지점을설정하시오. 2. 함수 func1 의시작부분에정지점을설정하시오. 3. 함수 main 의 if 문블록의첫문장에서정지점을설정하되 global_value 값이 0 일때만작동하도록설정하시오. 4. 문제 1 에서설정한정지점을잠시해제하시오. 5. 문제 4 에서잠시해제한정지점을활성화하시오. 40 System Security Lab@Myongji Univ.
감시점 (watch point) 설정 : watch 감시점설정 : watch watch [ 변수명 ] 변수의값이바뀔때마다정지하면서변수의이전값과현재값을출력 (gdb) watch p Hardware watchpoint 2: p (gdb) c Hardware watchpoint 2: p Old value = 100 New value = 101 0x0804800d in main () at qsort.c: 32 32 p = p + 1; (gdb) 41 System Security Lab@Myongji Univ.
감시점설정 감시점설정 rwatch [ 변수명 ] 변수의값이읽혀질때마다정지하면서변수의이전값과현재값을출력 awatch [ 변수명 ] 변수의값이읽기, 쓰기될때마다정지 42 System Security Lab@Myongji Univ.
변수보기 변수보기 명령어 info locals info variables print (p) [ 변수명 ] print [ 함수명 ] print 파일명 :: 변수명 print 함수명 :: 변수명 whatis [ 변수명 ] 의미현재상태에서지역변수들의정보전역변수들의정보변수의값을출력함수의주소를출력특정파일의전역변수값을출력특정함수의 static 변수값을출력변수의타입을출력 43 System Security Lab@Myongji Univ.
변수보기 출력형식지정하기 print 명령은기본적으로 10 진수로출력 2 진수, 16 진수등으로출력하고싶을때 명령어 print/t 변수명 print/o print/d print/u print/x print/f print/c print/s 의미 2진수로출력 8진수로출력부호가있는 10진수로출력부호가없는 10진수로출력 16진수로출력부동소수점형식으로출력문자 (ASCII) 로출력문자열로출력 44 System Security Lab@Myongji Univ.
변수보기 변수값을자동으로출력하기 : display step 명령등으로실행할때마다자동으로변수값을출력 display 가설정되면출력번호가붙여진다. 명령어 display [ 변수명 ] display/[ 출력형식 ] [ 변수명 ] undisplay [ 번호 ] disable display [ 번호 ] enable display[ 번호 ] 의미변수값을자동으로출력변수값의출력형식을지정출력설정을없앤다출력을일시중단출력을활성화 (gdb) display p 1: p = 100 (gdb) display array[i] 2: array[i] = (gdb) display gtime.hour 3: gtime.hour = 1 45 System Security Lab@Myongji Univ.
변수값설정 변수값설정 : print (gdb) print p $5 = 100 (gdb) print p = 1000 $6 = 1000 (gdb) print p $7 = 1000 46 System Security Lab@Myongji Univ.
레지스터보기 레지스터보기명령어의미 info registers (reg) 레지스터들의값을출력 print $[ 레지스터명 ] 특정레지스터의값을출력 (gdb) print $eax $11 = 15 (gdb) print $ebx $12 = 20 47 System Security Lab@Myongji Univ.
스택보기 현재스택내용보기 : info frame (info f) 현재실행중인함수의스택프레임내용을출력 스택프레임의내용 : 함수의매개변수, 지역변수, 반환될주소 전체스택프레임목록보기 : backtrace (bt) bt 전체스택프레임출력 bt N bt -N bt full 최초 N 개의프레임만출력 마지막 N 개의프레임만출력 스택프레임과지역변수를출력 48 System Security Lab@Myongji Univ.
스택보기 backtrace (cont.) (gdb) bt #0 0x4207a42b in strlen ( ) from /lib/tls/libc.so.6 #1 0x4204752d in vfprintf ( ) from /lib/tls/libc.so.6 #2 0x4204f112 in printf ( ) from /lib/tls/libc.so.6 #3 0x080483bc in main ( ) at qsort.c:33 #4 0x42015574 in libc_start_main ( ) from /lib/tls/libc.so.6 (gdb) 49 System Security Lab@Myongji Univ.
스택보기 스택관련명령어 명령어 info frame info args info locals frame [ 프레임번호 ] up down backtrace 의미현재함수의스택프레임내용을출력현재함수의인자를출력현재함수의지역변수를출력해당번호의스택프레임으로변경상위스택프레임으로이동하위스택프레임으로이동모든스택프레임목록을출력 50 System Security Lab@Myongji Univ.
메모리내용보기 메모리내용보기 : x x[ 범위 ][ 출력형식 ][ 범위의단위 ] [ 메모리주소 ] 명령어예 x main x 0x80482da 의미 함수 main 의주소에서 4 바이트내용출력 주소 0x80482da 에서 4 바이트내용출력 x/10 main 함수 main 의주소에서 40 바이트내용출력 x/10i main x/10b 0x80482da 함수 main 의주소에서 40 바이트내에있는명령어들을어셈블리어로변환하여출력 주소 0x80482da 에서 10 바이트내용출력 51 System Security Lab@Myongji Univ.
메모리내용보기 출력형식심볼의미 t 2진수로출력 o 8진수로출력 d 부호가있는 10진수로출력 u 부호가없는 10진수로출력 x 16진수로출력 f 부동소수점형식으로출력 s 문자열로출력 i 어셈블리어로출력 범위단위심볼의미 b 1 바이트단위 h 2 바이트단위 w 4 바이트단위 g 8 바이트단위 52 System Security Lab@Myongji Univ.
메모리내용설정 메모리내용설정 : set set { 타입 }[ 주소 ] = [ 값 ] 타입 : C 언어의데이터타입 (int, double, char 등 ) 명령어예 의미 set {int}0x8048100 = 100 주소 0x8048100 번지에 int 크기인 4 바이트공간에 100 을저장 (gdb) set {int}0x8048100 = 100 (gdb) x/d 0x8048100 0x8048100 <func+32>: 100 53 System Security Lab@Myongji Univ.
어셈블리코드보기 어셈블리코드보기 : disassemble (disas) 명령어예 disas main disas 0x80482da 의미 함수 main 의어셈블리코드출력 주소 0x80482da 에서어셈블리코드출력 54 System Security Lab@Myongji Univ.
프로세스의메모리맵보기 현재디버깅중인프로세스의메모리맵보기 info proc mapping 코어파일로디버깅중인프로세스의메모리맵보기 info files 또는 info target 55 System Security Lab@Myongji Univ.
함수호출및분기 함수호출 : call 명령어예 call qsort call qsort(100) 의미 함수 qsort 호출 함수 qsort 에인자 100 을사용하여호출 분기 : jump 명령어예 jump 10 jump *0x8048100 jump qsort 의미 10행으로분기하여실행주소 0x8048100으로분기하여명령어실행함수 qsort로분기하여실행 56 System Security Lab@Myongji Univ.
실습 1. 예제프로그램 (myprog) 을실행하면어디에서수행이멈추었는가? 2. 지역변수를출력하시오. 3. *local_str 값은무엇인가? 4. local_value 의주소값은무엇인가? 5. 현재스택프레임의내용을출력하시오. 57 System Security Lab@Myongji Univ.
실습 (cont.) 6. 현재스택프레임에서 Locals 는어느주소에서시작하는가? 7. 전역변수를출력하시오. 8. 전역변수 global_value 의주소값을출력하시오. 9. 전역변수 global_value 의값을출력하시오. 10.c_Prog 의값을출력하시오. 58 System Security Lab@Myongji Univ.
실습 (cont.) 11.C_prog 의멤버 page 의값을출력하시오. 12.Continue 명령을입력하여수행하면, 어디에서수행이멈추는가? 13. 전체스택의트레이스를출력하시오. 14. 현재스택프레임내용을출력하시오. 15. 현재함수의인자를출력하시오. 59 System Security Lab@Myongji Univ.
실습 (cont.) 16. 이제 next 명령어를이용하여계속수행해보시오. 17. 이제어디에서수행이멈추었는가? 이때출력된메시지는무엇인가? 18. 프로그램의오류는무엇인가? 60 System Security Lab@Myongji Univ.
쓰레드디버깅 쓰레드디버깅관련명령어 명령어예 info threads b [ 행번호 M] thread [ 쓰레드번호 N] thread [ 쓰레드번호 N] 의미 수행중인쓰레드정보를출력 쓰레드 N 의코드에서행번호 M 에정지점설정 현재디버깅쓰레드를 N 으로변경 61 System Security Lab@Myongji Univ.
기타 62
시스템콜디버깅 strace 프로그램이수행하는중에사용하는시스템콜을출력해준다. 예 ) like 를수행시키고 like 가사용하는시스템호출과시스템콜의반환값을보여줌 $ strace./like 현재수행중인프로세스도확인해볼수있다. 예 ) PID 가 2000 번인프로세스가사용하는시스템호출을보여줌 $ strace p 2000 63 System Security Lab@Myongji Univ.
라이브러리호출디버깅 ltrace 프로그램이수행중에호출하는공유라이브러리와라이브러리의반환값을보여준다. $ ltrace./like 사용하는시스템콜까지보고싶다면, $ ltrace S./like 64 System Security Lab@Myongji Univ.
디버깅용매크로 디버깅에유용한매크로 LINE : 현재문장번호 FILE : 현재파일이름 DATE : 현재날짜 TIME : 현재시간 #include <stdio.h> main() { } printf( line %d of file %s \n, LINE, FILE ); 65 System Security Lab@Myongji Univ.
assert() 를이용한디버깅 assert 함수 #include <assert.h> void assert(expression) expression 의결과가참이아니면오류메시지를출력하고프로그램을종료한다. 오류메시지에는오류가발생한소스파일이름, 함수이름, 줄번호가포함되어디버깅에유용함 만약 NDEBUG를 define하면 assert는수행되지않는다. #define NDEBUG 또는 gcc -DNDEBUG 66 System Security Lab@Myongji Univ.