Page 1
복습● echo “file1” > file1
● echo “file2” > file2
● echo -e “asdf\nlkj” > file3
● cat file3
● grep lk file3 | cat file1 – file2
● grep lk file3 | cat /dev/fd/0 file1 file2
Integrated Development Environment (IDE)
C++ source code
MakefileProject file
object code (binary, one per compilation unit) .o
make“make” utility
Runtime/utility libraries
(binary) .lib .a .dll .so
gcc, etc.compiler
linklinker executable
program
debugger
link
An “IDE”
compile
gdb
Eclipse
Visual Studio
Make and gdb
Page 4
Index
makegdb
Page 5
make
Page 6
Contents
What is make Makefile 내용 매크로 기능 레이블 기능 매크로와 확장자 References
Page 7
What is vi
Make 유틸리티만든다 ?– 프로그램 그룹을 유지하는데 필요한 유틸리티– 명령어 방식으로 처리되는 모든 곳에서 쓰일 수 있다 .– Makefile 은 make 가 이해할 수 있도록 일종의 쉘 스크립트 언어같이 되어있다 .
필요성– 프로그램 개발에서 여러 파일과 관계있는 하나의 함수를 바꾸게 되었을 때 그 파일에 있는 함수를 이용하는 다른 파일도 새롭게 컴파일되어야 한다 .– 파일 수가 많은 경우 불편함이 생기고 실수가 생기게 된다 .
Make – GNU make utility to maintain groups of programs
Page 8
Dependency (simple case)
gcc -o program main.c bill.c fred.c
lib.hmain.c
bill.c
fred.c
program
Page 9
Dependency (simple case)
gcc -o program main.c bill.c fred.c
lib.hmain.c
bill.c
fred.c
program
Slow!!!
fred.c 만 바뀌어도 모든 소스코드를 다시 컴파일 함 .
Page 10
Dependency (in the case of a static library)
lib.hmain.c
bill.c
fred.c
main.o
bill.o
fred.o
libfoo.a
program
What have to be rebuilt when fred.cfred.c has modified?
Page 11
Makefile 의 내용 Makefile 의 내용
– makefile 은 목표 (target), 의존 관계 (dependency), 명령 (command) 의 세개로 이루어진 기본적인 규칙 (rule) 들이 계속적으로 나열되어있는 형태이다 .– 명령 부분은 꼭 TAB 글자로 시작해야 한다 . · · ·
target · · · : dependency · · ·command · · · · · ·
Page 12
Makefile 예제 간단한 Makefile
$ gcc –c main.c$ gcc –c read.c$ gcc –c write.c
$ gcc –o test main.o read.o write.o
test : main.o read.o write.ogcc –o test main.o read.o write.o
main.o : io.h main.cgcc –c main.c
read.o : io.h read.cgcc –c read.c
write.o : io.h write.cgcc –c write.c
Page 13
매크로의 사용 매크로 기능
test : main.o read.o write.ogcc –o test main.o read.o write.o
main.o : io.h main.cgcc –c main.c
read.o : io.h read.cgcc –c read.c
write.o : io.h write.cgcc –c write.c
OBJECTS = main.o read.o write.o
test : $(OBJECTS)gcc –o test $(OBJECTS)
main.o : io.h main.cgcc –c main.c
read.o : io.h read.cgcc –c read.c
write.o : io.h write.cgcc –c write.c
Page 14
레이블의 사용 레이블 기능
test : main.o read.o write.ogcc –o test main.o read.o write.o
main.o : io.h main.cgcc –c main.c
read.o : io.h read.cgcc –c read.c
write.o : io.h write.cgcc –c write.c
OBJECTS = main.o read.o write.o
test : $(OBJECTS)gcc –o test $(OBJECTS)
main.o : io.h main.cgcc –c main.c
read.o : io.h read.cgcc –c read.c
write.o : io.h write.cgcc –c write.c
clean :rm $(OBJECTS)
Page 15
매크로와 확장자 규칙 미리 정해져 있는 매크로
ASFLAGS = ← as 명령어의 옵션 세팅AS = asCFLAGS = ← gcc 의 옵션 세팅CC = cc (=gcc)CPPFLAGS = ←g++ 의 옵션CXX = g++LDLFAGS = ←ld 의 옵션 세팅LD = ldLFLAGS = ←lex 의 옵션 세팅LEX = lexYFLAGS = ←yacc 의 옵션 세팅YACC = yaccMAKE_COMMAND = make
Page 16
test : main.o read.o write.ogcc –o test main.o read.o write.o
매크로와 확장자 규칙 예제
OBJS = main.o read.o write.o
test : $(OBJS) ← 중복 제거 (.o 파일 추가시 첫줄만 수정 )gcc –o test $(OBJS)
OBJECTS = main.o read.o write.oSRCS = main.c read.c write.c
CC = gcc ← gcc 로 세팅CFLAGS = -g –c ← gcc 의 옵션에 – g 추가TARGET = test ← 결과 파일을 test 라고 지정$(TARGET) : $(OBJECTS)$(CC) –o $(TARGET) $(OBJECTS)
clean :rm –rf $(OBJECTS) $(TARGET) core
main.o : io.h main.cread.o : io.h read.cwrite.o : io.h write.c
Version 1
Version 2
Version 3
Page 17
매크로와 확장자 규칙 확장자 규칙
– 파일의 확장자를 보고 , 그에 따라 적절한 연산을 수행시키는 규칙.SUFFIXES : .c .o
OBJECTS = main.o read.o write.oSRCS = main.c read.c write.c
CC = gcc CFLAGS = -g -c INC = -I/home/raxis/include
TARGET = test
$(TARGET) : $(OBJECTS)$(CC) –o $(TARGET) $(OBJECTS)
%.o : %.c io.h$(CC) $(INC) $(CFLAGS) $<
clean :rm –rf $(OBJECTS) $(TARGET) core
← include 패스 추가
<- 사용자가 확장자 규칙을 구현 ($< 는 소스파일을 의미함 )
Version 4
Page 18
Makefile
main.c
read.c
write.c
io.h
Page 19
References
makefile Full Guide– http://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-1.html
makefile Tutorial– http://www.opussoftware.com/tutorial/TutMakefile.htm
List of Commands – http://www.smashingmagazine.com/2010/05/03/vi-editor-linux-terminal-cheat-sheet-pdf/
Page 20
gdb
Page 21
Contents
What is gdb? gdb 의 사용법
References
10/2/19
Page 22
What is gdb?
디버거의 목적 ? – 프로그램 실행동안 프로그램 내부에서 진행되고 있는 것이 무엇인지를 알도록 하는데에 있다 . ( 또는 다른 프로그램이 종료되는 순간에 무엇을 했는지 )
gdb 의 목적 ?– 프로그램을 시작할 때 프로그램의 행동에 영향을 줄 수 있는 것을 지정할 수 있다 .– 프로그램을 지정된 조건에서 멈추도록 만든다 .– 프로그램이 멈추었을 때 무엇이 일어났는지를 시험할 수 있다 .– 프로그램내의 어떤 인자를 바꾸어서 , 버그를 고칠 수 있도록 실험을 할 수 있게 하고 다른것에 대해 배우도록 한다 .
Page 23
디버그용 컴파일 하기 컴파일 하기
– 디버그 하기 전에 , 디버그 하고자 하는 프로그램에 디버깅 정보를 컴파일 한다 . Gdb 가 사용했던 변수 , 라인 및 함수를 실행할 수 있게 된다 . Gcc 에서 ‘ g’ 옵션을 이용하여 프로그램을 컴파일 한다 .$ gcc –g example.c –o example
Page 24
gdb 실행하기 gdb 실행하기
– gdb 는 쉘에서 ‘ gdb’ 명령으로 실행된다 . gdb 에서 파일 명령으로 디버깅 용 프로그램을 로드할 수 있다 . ( 예 : ‘file example’).– 프로그램과 동일한 디렉토리에서 명령이 실행되어 , 일단 로드 되면 gdb command인 ‘ run’ 으로 프로그램이 시작한다 .
Linux 사용자의 경우 cgdb 를 사용하면 더 편함 .
설치 방법 :sudo apt-get install cgdb
Page 25
디버깅 세션의 예제 예제코드
– 루프문을 통해 곱셈 결과를 출력하고 , 마지막에 assert 문을 이용하여 강제로 오류를 발생시켜 종료하는 프로그램#include <stdio.h>#include <assert.h>int test(){ int i = 0; int j = 0; for( i = 0; i < 4; ++i ) for( j = 0; j < 4; ++j ) printf( "%d x %d = %d\n", i, j, i * j ); }int main(){
int k=0;test();
assert( 0 ); exit( 0 );}
Page 26
디버깅 세션의 예제 디버깅 정보를 삽입하여 컴파일
– gdb 정보와 함께 (gdb) 콘솔 command 창으로 바뀐다 .– gdb 상에서 이 예제 프로그램을 실행한다 . 명령어는 ‘ run’ 이다 .
$ cc -g -o gdb_test gdb_test.c $ gdb gdb_test또는$ cgdb gdb_test
Page 27
디버깅 세션의 예제– assert 문 때문에 SIGABRT 시그널 메시지와 함께 프로그램이 종료됨–
– 함수 호출에 대한 스택 추적은 ‘ backtrace’ 또는 'bt' 를 통해 확인할 수 있다 .
Page 28
디버깅 세션의 예제– main ☞__assert_fail ☞ abort() ☞ raise() ☞ __kernel_vsyscall() 순으로 함수 호출을 확인
– 해당 프로그램의 소스를 보기 위해 ‘ list’ 을 입력
Page 29
디버깅 세션의 예제– 브레이크 포인트 위치 설정
– 재실행 하여 브레이크 포인트 확인
– run 을 해보면 해당 라인에서 프로그램이 gdb 로 제어권이 넘어온다 .– ‘print’ 명령을 사용하여 각 변수의 값을 확인할 수 있다 .– ‘display’ 명령은 한번 설정해두면 변수의 값을 각 단계마다 자동적으로 보여준다 .– 브레이크 포인트부터 이어서 수행하려면 ‘ cont’ 를 입력한다 .– step 과 next– step : 함수의 내부까지 추적해 들어간다 . ‘s’ 로 실행– next : 해당 함수를 한 줄로 보고 그 다음 줄로 넘어간다 . ‘n’ 로 실행– finish: 해당 함수가 끝날때까지 실행 'fin' 로 실행
Page 30
b 9 (9번째 줄에 브레이크 설정 )run
Page 31
b main (main 함수에 브레이크 설정 )run
Page 32
디버깅 세션의 예제– 브레이크 포인트 위치 확인 및 해제
– 현재 설정된 브레이크에 대한 정보는 ‘ info break’ 로 확인 .– 설정한 브레이크 지점은 ‘ disable’ 을 사용하여 해제할 수 있다 .– disable 로 브레이크를 해제하는 지점은 라인번호가 아니라 설정 순서의 번호이다 . (info 로 확인했을 때의 번호 )
Page 33
프로그램 작업 디렉토리cd directory
GDB 작업 디렉토리를 directory 로 설정한다 .
pwdGDB 작업 디렉토리를 출력한다 .
Page 34
이미 실행중인 프로세스 디버깅하기attach process-id작동중인 프로세스를 연결시킨다 . (GDB 밖에서 시작된 프로세스 )
detachGDB 제어에서 프로세스를 놓아준다 .
Page 35
자식 프로세스 죽이기kill
Page 36
브레이크 포인트 설정break function
break +offset
break –offset
break linenum
break filename:linenum
break *address
tbreak args
hbreak args
thbreak args
rbreak regex
Page 37
스택 프레임– 콜 스택은 stack frames 또는 frames 라 불리는 연속적인 조각으로 나누어진다 .– 각 프레임은 하나의 함수에 하나의 호출이 관련된 데이터이다 .– 프레임은 함수에 주어지는 인자와 함수의 지역 변수들 그리고 함수가 실행하는 주소를 포함한다 .
frame argsframe 명령어는 한 스택 프레임에서 다른 스택 프레임으로 이동하도록 하며사용자가 선택한 스택 프레임을 출력한다 .
select-frame프레임 출력 없이 한 스택 프레임에서 다른 스택 프레임으로 이동하도록 한다 .
Page 38
Page 39
backtraces
– 프로그램이 어떻게 돌아가는지에 대한 요약이다 .– 현재 실행되는 프레임에서 시작하여 호출자 ( 프레임 1) 가 뒤따라오고 그리고 스택위에 있는 많은 프레임을 위해 프레임당 한 라인씩 보여준다 .
backtracebt 전체 스택에 대한 backtrace 를 보여준다 .
backtrace nbt n
innermost n 프레임만을 출력한다backtrace –nbt –n
outermost n 프레임만 출력한다 .
Page 40
프레임 선택하기– 프로그램에서 스택이나 다른 데이터를 검사하는 대부분의 명령어들은 그 순간에 선택된 스택 프레임에서 작동한다 .
frame nf n 프레임 넘버 n 을 선택한다 .
frame addrf addr프레임 주소 addr 을 선택한다 .
up n 스택위 n 프레임으로 이동하라 .
down n스택 아래 n 으로 이동하라 .
Page 41
소스 라인 출력하기– 소스 파일에서 라인을 출력하기 위해 list 명령어를 사용한다 .– 기본적으로 10 라인이 출력된다 .– 출력하기를 원하는 파일의 일부를 지정하기 위한 여러 가지 방법이 있다 .
list linenum현재 소스 파일에서 라인넘버 linenum 을 가운데로 라인을 출력한다 .
list function함수 function 시작 근처를 가운데로 라인을 출력한다 .
list 라인들을 더 출력한다 .
list – 마지막으로 출력된 라인의 전 몇 라인을 출력한다 .
set listsize countlist 명령어는 count 소스 라인을 출력한다 .
show listsizelist 가 출력하는 라인 넘버를 출력한다 .
Page 42
소스 파일 찾기– 정규식 표현식을 위해 현재 소스 파일 탐색을 위해 두개의 명령어가 있다 .
forward-search regexpsearch regexp명령어 ‘ forward-search regexp’ 는 regexp 과의 매치를 위해 ,나열된 마지막 라인 다음으로 시작하는 각 라인을 검사한다 .
reverse-search regexp‘reverse-search regexp’ 는 regexp 과의 매치를 위해 ,나열된 마지막 라인전에 시작하고 뒤로 가는 각 라인을 검사한다 .
Page 43
소스 디렉토리 지정하기– 실행 프로그램은 가끔 컴파일된 디렉토리에서 소스 파일의 디렉토리를 기록하지 않는다 .– 컴파일될때 , 디렉토리들은 컴파일과 디버깅 세션 사이에 이동될 수 있다 .– GDB 는 소스파일을 찾기 위한 디렉토리 리스트를 가지고 있다
directory dirname …dir dirname …디렉토리 dirname 을 소스 경로의 앞에 추가한다 .
directory소스 경로를 비게한다 .
show directories소스 경로를 출력한다 .
Page 44
데이터 검사하기– 프로그램에서 데이터를 검사하기 위한 일반적인 방법은 print 명령어나 동의어인 in-
spect 이다 .print expprint /f exp
exp 는 표현식이다 .기본적으로 exp 값은 데이터 타입에 맞는 포맷으로 출력한다 .
printprint /f
exp 를 생략한다면 , GDB 는 마지막 값을 다시 출력한다 .
Page 45
표현식– print 와 많은 다른 GDB 명령어들은 표현식을 받아들이며 그 값을 계산한다 .– 사용하는 프로그래밍 언어에 의해 정의된 상수 , 변수 또는 연산자는 GDB 의 표현식에서 유효하다 .– 이것은 추가적인 표현식 , 함수 호출 , 캐스팅 그리고 문자열 상수를 포함한다 .– 전처리기 #define 명령어들에 의해 정의된 심볼들은 포함되지 않는다 .
@‘@’ 는 배열로써 메모리의 일부를 다루기 위한 이진 연산자이다 .
::‘::’ 는 이것이 정의된 파일이나 함수내 변수를 지정하도록 허용한다 .
{type} addr메모리에 있는 주소 addr 에 저장되어 있는 객체 타입 type 을 가리킨다 .
Page 46
프로그램 변수들– 사용시 가장 일반적인 표현은 대부분의 프로그램에서 변수 이름이다 .– 표현식에서 변수들은 선택된 스택 프레임에서 이해된다 .
– 프로그램이 이미 함수 foo 내에서 실행될 때는 언제나 변수 a 를 시험하고 사용할 수 있다 .– 그러나 프로그램이 b 가 선언된 블럭내에서 실행되는 동안 b 만을 사용하고 검사할 수 있다 .
global (or static)또는 프레임내 실행 시점에서 프로그램의 영역 규칙에 따라 보여진다 .이것은 함수내에서 의미가 있다 .
void foo ( int a){
bar (a);{
int b = test ();bar (b);
}}
Page 47
인공배열– 이것은 메모리내 같은 타입의 연속적인 객체들을 출력하는데 유용하다 .
int *array=(int *) malloc (len * sizeof (int));사용자는 array 의 내용을 출력할 수 있다 .
p *array@len‘@’ 의 왼쪽 피연산자는 메모리에 남아있다 .이 방법으로 ‘ @’ 하고 같이 만든 배열 값들은 다른 배열들 처럼 행동한다 .그리고 표현식에서 사용될 때 포인터를 마음대로 할 수 있다 .
인공배열을 만들기 위한 다른 방법은 형변환을 사용하는 것이다 .(gdb) print /x (short[2])0x12345678 또는(gdb) p/x (short[2])0x12345678$1 = {0x1234, 0x5678}
배열의 길이를 뺀다면 (`(type)[])value‘)GDB 는 그 값을 채우기 위해 크기를 계산한다 . (`sizeof(value)/sizeof(type)':
(gdb) p/x (short[])0x12345678$2 = {0x1234, 0x5678}
Page 48
출력 형식– 기본적으로 GDB 는 데이터 타입에 따라서 값을 출력한다 .
x 정수로써 값을 간주한다 . 그리고 16 진수로 정수를 출력한다 .d 부호화된 10 진수 정수로 출력한다 .u 부호화되지 않은 10 진수 정수로 출력한다 .o
8 진수 정수를 출력한다 .t 이진수로 정수를 출력한다 . 문자 ‘ t’ 는 ‘ two’ 를 나타낸다 .a
16 진수로 주소와 그리고 가장 가까운 전 심볼에서 오프셋을 출력한다 .c 정수로 간주하고 문자 상수로써 출력한다 .f 부동 소수점 수로 값을 간주하고 전형적인 부동 소수점 문접을 사용하여 출력한다 .
Page 49
메모리 검사하기– 프로그램의 데이터 타입에 의존하지 않고 여러 형식으로 메모리를 검사하기 위해 x 명령어를 사용할 수 있다 .
x/nfu addrx addrx 메모리를 검사하기 위해 x 명령어를 사용해라n, 반복수반복 수는 10 진 정수이다 .f, 출력 형식출력 형식은 print ‘s’(null 로 끝난 문자열 ),또는 ‘ I’( 기계어 ) 가 사용한 형식중 하나이다 .u, 단위 크기단위 크기는 다음과 같다 .
b : 바이트h : 2 바이트 (half word)w : 워드 (4 바이트 ). 기본값이다 .g : 8 바이트 (giant word)
Page 50
자동 디스플레이– 표현식 값을 자주 출력하기를 원한다면 , gdb 가 프로그램을 멈출 때 마다 해당 값을 출력하도록 하기 위해 표현식을 자동 디스플레이 리스트에 추가한다 .
display exp프로그램이 멈출 때 마다 출력하기 위해 표현식 리스트에 표현식 exp 를 추가display /fmt exp
fmt 로 출력 포맷만을 지정하고 크기와 카운트는 지정하지 않기 위해 ,표현식 exp 를 자동 디스플레이 리스트에 추가한다 .
display /fmt addrfmt ‘I’ 나 ‘ s’, 또는 단일 크기나 유닛의 수를 포함하기 위해 ,프로그램이 멈출 때 마다 검사하기 위한 메모리 주소로써 표현식 addr 을 추가
Page 51
print 설정하기– GDB 는 배열 , 구조체 그리고 심볼들을 출력하는 방법을 제어하기 위해 다음 방법을 제공한다 .
set print addressset print address on
GDB 는 스택 발자취 , 구조체 값 , 포인터 값 , breakpoints 등등의 주소를나타낼 때 조차 이들의 위치를 보여주는 메모리 주소를 출력한다 .
set print address off내용들을 출력할 때 주소를 출력하지 마라 .
show print address주소를 출력할지 안할지를 보여준다 .
set print symbol-filename on소스파일 이름과 주소의 symbol 형태에 있는 symbol 의 라인 수를 출력하게한다 .
set print symbol-filename off소스파일 이름과 symbol 의 라인 수를 출력하지 말아라 .
show print symbol-filenameGDB 가 소스파일 이름과 주소의 symbol 형태에 있는 symbol 의 라인수를 출력할지안할지를 보여준다 .
CGDB 전용 단축키(vi 처럼 edit mode, insert mode 가 있음 )
● <esc> : goto source window ↔ i : goto gdb window
● Source window shortcuts:
– <F5> :run
– <F6> :continue
– <F7> :finish
– <F8> :next
– <F10> :step
( 동작 안하면 단축키 변경이 필요함 )
예 :map <F2> :step<CR>
– gg : Move to the top of file.
– G : Move to the bottom of file.
– / : search from current cursor position.
– ? : reverse search from current cursor position.
– n (N) : next forward (reverse) search.
– o : open the file dialog.
– <space> : toggle breakpoint
–
Page 53
References
GDB Full Guide– http://korea.gnu.org/manual/release/gdb/gdb.html
Simple Guide– http://hermet.pe.kr/88589788
Page 54
Quiz
● 다음장의 프로그램 컴파일 (make)
● io.h 를 수정후 make 했을때 다시 만들어지는 파일은 ?
● main.c 를 수정후 make 했을때 다시 만들어지는 파일은 ?
● cgdb 를 이용하여 버그를 찾고 수정하시오 .
Page 55
Makefile
main.c
read.c
write.c
io.h
Carnegie Mellon
C-1
int main() {int* a = malloc(100*sizeof(int));for (int i=0; i<100; i++) {
if (a[i] == 0) a[i]=i;else a[i]=0;
}free(a);return 0;
}
Carnegie Mellon
C-2
int main() {char w[strlen("C programming")];strcpy(w,"C programming");printf("%s\n", w);return 0;
}
Carnegie Mellon
C-3
struct ht_node {int key;int data;
};typedef struct ht_node* node;
node makeNnode(int k, int e) {node curr = malloc(sizeof(node));node->key = k;node->data = e;return node;
}
Carnegie Mellon
C-4
char *strcdup(int n, char c) {char dup[n+1];int i;for (i = 0; i < n; i++)
dup[i] = c;dup[i] = ’\0’;char *A = dup;return A;
}
Carnegie Mellon
C-5
#define IS_GREATER(a, b) a > binline int isGreater(int a, int b) {
return a > b ? 1 : 0;}int m1 = IS_GREATER(1, 0) + 1;int m2 = isGreater(1, 0) + 1;
Carnegie Mellon
C-6
#define NEXT_BYTE(a) ((char*)(a + 1));
long a1 = 54; // &a1 = 0x100int a2 = 42; // &a2 = 0x200void* b1 = NEXT_BYTE(&a1);void* b2 = NEXT_BYTE(a2);
Carnegie Mellon
C-7
#define NEXT_BYTE(a) ((char*)(a + 1));
int a1 = 54; // &a1 = 0x100long long a2 = 42; // &a2 = 0x200void* b1 = NEXT_BYTE(&a1);void* b2 = NEXT_BYTE(&a2);
b1 is a void pointer to the address 0x104.b2 is a void pointer to the address 0x108.