정글/Pintos

[pintos] gdb를 사용해보세요 - gdb 사용법

nkdev 2025. 5. 29. 23:06

우리반에 몇 없는 gdb 사용자 김윤호씨에게 감사를 전하며 글을 시작하겠습니다 ദ്ദി˙∇˙)

도커환경을 실행시키고 있는 터미널 2개 켜기

 

현재 실행 중인 도커 목록을 확인한다.

docker ps -a 

 

그 중 접속할 도커 이미지를 선택해서 도커 환경에 접속한다.

docker exec -it [docker container ID] /bin/bash

 

userprog/build 디렉토리로 이동한다.

 

나는 build 디렉토리 안에 이미 목적 파일이 생성되어 있는데, 아직 없다면 make 명령어로 컴파일해주자.

 

참고로 docker exec ~ 명령은 이미 실행 중인 컨테이너에 새 터미널을 attach하는 것일 뿐 docker run으로 새로운 컨테이너를 만드는 게 아니므로, 해당 컨테이너에서 이미 빌드한 목적 파일이나 바이너리 등이 있다면 attach shell에서 공유하며 볼 수 있다. 

 

파일 디스크 만들기

이제 gdb 연결을 받을 터미널을 먼저 실행시키기 전에 우리는 파일 디스크가 필요하다. 

*

파일 디스크 만드는 작업을 하다가 알게된 건데, 이렇게 직접 파일 디스크를 만들어줄 수도 있지만 userprog/build에 정의되어 있는 Makefile을 이용하여 컴파일하면 os.dsk라는 파일 디스크가 하나 만들어진다. 그냥 얘를 쓰면 될 것 같다. 


 

갑자기 파일 디스크를 왜 만드는지 궁금하다면 !

Pintos 공식문서의 GitBook > Project2 > Introduction > Using the File System 을 참고하면 알 수 있다.

https://casys-kaist.github.io/pintos-kaist/project2/introduction.html

 

Introduction · GitBook

Project2: User Programs Now that you've worked with Pintos and are becoming familiar with its infrastructure and thread package, it's time to start working on the parts of the system that allow running user programs. The base code already supports loading

casys-kaist.github.io

https://cs162.org/static/proj/pintos-docs/docs/overview/filesystem/

 

이렇게 pintos-mkdisk를 이용하여 파일 디스크 이미지를 생성하고 포맷하는 이유는 핀토스가 사용할 디스크를 물리적인 저장 장치가 아닌 파일로 만들기 위해서이다. 이 파일은 QEMU가 디스크처럼 인식하게 되며, 운영체제가 파일 시스템을 올릴 수 있는 대상이 된다.


암튼 파일 디스크를 하나 생성해보자.

src/utils에 정의된 pintos-mkdisk라는 도구를 사용한다. 2는 크기를 지정해준 건데 2MB 크기를 생성해주겠다는 뜻이당.

$ pintos-mkdisk filesys.dsk 2

 

현재 pwd가 userprog/build이므로 상대 경로로 utils까지 간 후 실행해준다.

(utils 경로를 지정해주지 않으면 pintos-mkdisk command not found 에러가 뜬다.)

이제 filesys.dsk라는 이름을 가진 파일 디스크가 하나 생성되었다.


 

gdb 환경 접속하기

이제 이 이미지 파일을 이용해서 gdb를 listen(대기 상태)로 만들어서 gdb 요청 받을 준비를 하자.

 

 

나는 왜인지 pintos 명령어가 계속 안 먹혀서 상대경로로 util을 계속 지정해줬다.

=> 이 부분  알고 보니 root 디렉토리에서 source ./activate를 안 해줘서 생긴 문제였음! 실행해주니 build 경로에서 pintos 명령어 먹힌당

 

그리고 아래 명령어를 입력한다.

pintos --gdb -v -k -T 60 -m 20   --fs-disk=2 -p tests/userprog/args-single:args-single -- -q   -f run 'args-single onearg'

요 명령어는 사실 make tests/userprog/args-single.result처럼 테스트를 실행하면 콘솔에 

이렇게 출력되는 아이다. Makefile 덕분에 make tests만 하면 이 긴 실행 명령어가 자동으로 실행되고 있었던 것이라는 사실을 알 수 있다. 근데 우린 지금 gdb 디버깅 버전으로 테스트를 실행할 거니까 얘네를 복붙한 후 맨 앞에 --gdb를 붙여주면 된다.  

 

명령어를 간단하게 설명하면

  • --gdb : gdb 디버깅을 위한 포트 1234 열기
  • -v : verbose 모드로 출력을 더 자세히 보여줌
  • -k : kernel mode 부팅 - 커널을 qemu로 실행
  • -T 60 : 타임아웃 시간 60초로 설정
  • -m 20 : 가상 머신 메모리 크기 20MB로 설정
  • --fs-disk=2 : 파일 시스템 이미지 크기 2MB로 설정 (tests/userprog/args-single 프로그램이 이 디스크에 복사되어 실행됨)
  • -p tests/userprog/args-single:args-single : args-single 테스트 프로그램을 디스크에 업로드 (호스트상 바이너리 위치:게스트 내에서 사용할 실행파일 이름)
  • -- -q -f run args-single onearg : 이 부분이 Pintos 커널 안에 전달할 인자들임 !!
    • -- 이후부터는 Pintos 커맨드라인 인자
    • -q : 부트 후 자동 종료
    • -f : 파일 시스템 포맷
    • run args-single onearg : args-single이라는 테스트 실행파일을 실행하며 인자로 "onearg"를 전달

 

 

qemu-system-x86_64: -s: Failed to find an available port: Address already in use

즉 QEMU가 gdb 서버를 열기 위해 포트 1234를 사용하려고 했는데 이미 사용 중이라서 실패했다는 에러가 떴다.

 

pkill -f qemu-system-x86_64로 gdb 디버깅용 qemu 인스턴스를 다 죽이고 다시 포트를 열어보자. 

 

잘 열린다.

 

이제 다른 터미널에서 gdb kernel.o 로 gdb 환경을 열고

gdb 환경에서 l(줄 보기 명령어)을 누르면 init.c의 main 코드가 보인다.

현재 로딩된 디버그 심볼 (kernel.o) 안에서 main함수의 위치가 출력된 것이다.

 

* 디버그 심볼이란 디버거들이 갖고 있는 디버깅을 위한 정보(변수/함수/라인 등..)인데 gdb kernel.o 입력 시 디버그 심볼이 자동으로 메모리에 로딩된다고 한다. 디버그 심볼을 로딩했기 때문에 함수 이름, 파일 이름, 코드 라인 등의 정보를 바탕으로 다음과 같은 동작을 수행할 수 있다.

l main 입력 -> main함수 소스를 볼 수 있고, b main을 입력하면 main함수에 브레이크 포인트를 걸 수 있다.

 

그리고 listen 상태인 Pintos 프로그램에 접속해보자.

(gdb) target remote localhost:1234

gdb가 아직 정확한 심볼 정보를 qemu에서 받아오지 못한 상태지만 연결 자체는 성공했다는 의미이다.

 

gdb 사용하기

 

c를 입력하면 

실행이 계속 되면서 포트를 열어준 쪽에서 이렇게 실행 결과가 출력이 된다.

 

break [함수명]을 입력하면 특정 함수에 브레이크 포인트를 걸 수 있다.

break load로 load()함수에 bp를 걸고 n으로 한 줄씩 실행시켜보면 된다. !!!

나는 Cannot find bounds of current function 에러가 발생해서 해결하러 가야 한다... 아ㅏㅏㅏ

사용법은 여기까지 !

 

아 참고로..

 

pintos --gdb -v -k -T 60 -m 20 \
  --fs-disk=2 \
  -p tests/userprog/args-single:args-single \
  -- -q -f run args-single onearg

 

여기서 -T옵션 값을 크게 주는 게 좋다.. 나는 느릿느릿한 사람이라서 그런지 60초가 짧았다ㅎ

 

그리고 반복문을 만나면 억겁의 시간동안 n을 쳐야 하는데.....

제 노고가 보이세요?

 

지피티도 권장하지 않는 행동이니 여러분은 until [실행하고싶은 라인]으로 반복문 탈출하세요!!

 

그럼 디버깅 하러 가볼게요..........안녕!