운영체제/리눅스

[리눅스] GDB디버거_2

Cloud_Park 2022. 7. 24. 17:15

 

2022.07.11 - [운영체제/리눅스] - [리눅스] GCC 입문

2022.07.13 - [운영체제/리눅스] - [리눅스] GDB 디버거 _1

 

[리눅스] GDB 디버거 _1

2022.07.11 - [운영체제/리눅스] - [리눅스] GCC 입문 2022.07.13 - [클라우드/NHN Cloud] - [NHN Cloud] 인스턴스 생성하기 2018.11.16 - [클라우드/AWS] - (AWS) EC2 인스턴스 생성 [리눅스] GCC 입문 해당 글은..

base-on.tistory.com

 

backtrace

어플리케이션 프로그램 동작 중 문제 시 운영체제 설정 등을 통하여 코어 덤프파일을 남길 수 있고, 이를 디버깅하여 프로그램의 문제점을 문제 파악 → 개발 시 사용 ,운영은 로그파일로

하지만 코어 덤프파일을 남길 수 없는 환경에서 segfault 발생, SIGKILL 시그널 수신 등 문제점이 발생한 상황이거나 시스템 진당 등을 목적으로 의도적으로 backtrace를 남길 수 있다면 유용하게 활용할 수 있다.

#include <execinfo.h>

int backtrace (void **buffer, int size);

backtrace 함수는 포인터 목록으로 현재 스레드에 대한 backtrace를 가져와 정보를 버러에 넣습니다.

size는 버퍼 크기에 맞는 void* 요소의 수입니다.

리턴값은 확보된 버퍼의 실제 항목수이며 최대 크기입니다.

버퍼내의 포인터들은 실제로 스택을 감시하여, 얻은 반환 주소이며, 스택 프래임 당 하나의 변환 주소입니다.

backtrace_symbols

#include <execinfo.h>

char **backtrace_symbols ( void *const *buffer, int size);

backtrace_symbols 함수는 backtrace 함수에서 얻은 정보를 문자열 배열로 변환합니다.

인수 bufferbacktrace 함수를 통해 얻은 주소 배열에 대한 포인터 여야하며 size는 해당 배열의 항목 수입니다.

반환값은 배열 버퍼와 마찬가지로 크기 항목이 있는 문자열 배열에 대한 포인터입니다.

각 문자열에서 함수이름, 함수에 대한 오프셋, 실제 리턴주소 (16)진수가 포함됩니다.

함수 이름은 프로그램에서 사용할 수 있도록 링커에게 추가 플래그를 전달해야합니다 (-rdynamic)

backtrace_symbols의 반환값은 malloc함수를 통해 얻은 포이터이며 해당 포인터를 해제하는 것은 호출자의 책임입니다.

문자열에 충분한 메모리를 확보할 수 없는 경우 리턴값 NULL입니다.

backtrace_symbols_fd

#include <execinfo.h>

void backtrace_symbols_fd(void *const *buffer, int size , int fd);

backtrace_symbols_fs함수는 backtrace_symbols 함수와 동일한 변환을 수행합니다

호출자에게 문자열을 반환하는 대신 문자열 파일 디스크립터 fd에 한 줄에 하나씩 씁니다.

malloc 기능을 사용하지 않으므로 해당 기능이 실패할 수 있는 상황에서 사용할 수 있습니다.

 

 

예제코드

-파일명 backtrace_example
#include <stdio.h>
#include <execinfo.h>
#include <stdlih.h>

void print_trace(void){
	void *array[10];
	size_t size;
	char **strings;
	size_t i;

	size= backtrace(array,10);
	strings= backtrace(array,size)
	
	printf("Obtained %d stack frames.\n",size);

	for (i=1 ; i<size  ; i++)
		printf("%s \n",strings[i]);

	free(strings)
}

void dummy_function(void){

	print_trace();
}

int main(void){
	dummy_function();
	return 0 ;
}

=================
$ gcc -g backtrace_example.c -o backtrace_example -rynamic
$ ./backtrace_example
#

 

 

 

addr2line 명령은 주소를 파일 이름고 줄 번호로 변환하는데 사용된다.

addr2line 명령을 사용하여 기계어 명령 주소를 명령이 시작된 파일의 행에 매핑할 수 있다.

addr2line [option] [addr addr ....]

예를 들어 앞 부분에서 설명한 backtrace_example 실행의 결과의 주소값 하나가 0x400942일때

addr2line -e  backtrace_example 0x400942

해당하는 행이 나온다.

 

 

 

실전 팁

문제:

회사에서 리눅스 플랫폼에서 돌아가는 애플리케이션을 개발 중이다.

그런데 코드에 문제가 있는지 실행만하면 프로세스가 죽어버린다.

화면에 segfault 메시지가 출력되도록 할 수 없을까? 화면에 segfault 메시지는 출력되는데, 도대체 어느 코드에서 문제가 되는지 찾을 수 있을까?

 

 

 

 

해결책 1

흐름 절차에 따라 예상되는 지전에서 print를 찍고,화면에 찍히는 디버깅 출력한다.

해결책2

Segfault 메시지를 활용하여 GDB 디버깅한다.

 

위사진에 function_start 함수에서 문제가 발생한 것을 확인했고 주소값은

오른쪽아래 코드 중간의 first_to_space+0x1a 라는 주소값을 얻게 됐다.

$ gdb ./test
(gdb)list  *(first_to_space+0x1a)