목차
•
기초 사용법
lldb의 간단한 사용방법을 순서대로 알아보려한다.
1.
먼저 소스가 있는 디렉토리에서, 아래 명령어 처럼 -g flag를 붙여서 컴파일을 진행한다.
g++ -g my_source_file.cpp -o my_program
C++
복사
위와 같이 컴파일 flag를 붙여주게 되면, 컴파일 과정에서 디버깅 정보를 포함하게 된다. 이로써 가능한 동작들은 아래와 같다.
•
실행 중인 코드의 라인 번호를 알 수 있다.
•
실행 중인 함수의 이름을 알 수 있다.
•
변수의 현재 값이 무엇인지 알 수 있다.
•
함수의 호출 스택을 알 수 있다.
•
등등..
이 와 같이 디버깅에 유용한 정보가 포함되기 때문에 컴파일시 이를 포함하여 진행한다.
2.
LLDB를 실행하고 디버그 정보가 포함된 프로그램을 로드
lldb my_program
C++
복사
3.
아래의 예시 처럼 break point를 지정
b main(함수) 또는 b 39(line을 나타냄)
C++
복사
4.
실행
run
C++
복사
5.
이때, 여러 break point를 줬다면 아래 명령어로 지속 가능
continue(다음 루틴 실행) 또는 n(다음 라인 실행)
C++
복사
break point를 없애고 싶다면 아래 명령어 사용한다.
breakpoint list (해당 명령을 통해서 리스트 확인)
breakpoint delete 1 (포인트 번호로 삭제)
breakpoint delete (모든 포인트 삭제)
보통은 아래와 같이 줄여서 사용한다.
b del
JavaScript
복사
lldb로 데이터 섹션을 확인하는 방법
lldb를 통해 직접적으로 해당 코드의 영역을 알 수 없기 때문에, 간접적으로 확인하는 방법을 간단하게 알아보려한다.
1.
데이터, 텍스트 영역: image dump sections 명령어를 사용해서 데이터, 텍스트 영역을 확인할 수 있다. 명령어 실행시 뒤에 실행파일을 넣어주면 해당 파일의 섹션만 볼 수 있다.
2.
스택 영역 : 스택 영역은 일반적으로 현재 함수의 스택 프레임으로 찾을 수 있다. bt 명령으로 스택 프레임 목록을 확인하고 첫 번째에서 마지막 프레임 사이에 있다면 스택 영역에 속할 가능성이 높다.
3.
힙 영역 : 힙 영역의 주소는 동적으로 할당된 객체의 포인터를 통해 확인할 수 있다. 동적 할당된 객체 포인터와 비교하여 주소가 힙 영역에 속하는지 확인할 수 있다. (다른 방법을 못찾음..)
추가적인 명령어
print, disassemble, memory read 총 3가지 명령어들을 간단하게 알아보겠다.
해당 명령어는 특정 변수의 값을 출력해주는 역할을 한다.
기본적인 사용법은 다음과 같다:
arduinoCopy code
print <expression>
Plain Text
복사
또는 축약형:
cssCopy code
p <expression>
Plain Text
복사
예를 들어, int a = 5;라는 변수가 있고 해당 변수의 값을 출력하려면 다음과 같이 입력한다.
arduinoCopy code
print a
Plain Text
복사
또는 축약형:
cssCopy code
p a
Plain Text
복사
이 외에도 print 명령어를 사용하여 현재 스택 프레임의 함수 인자 값, 구조체 또는 클래스의 멤버 값을 확인할 수 있다.
disassemble
해당 명령어는 특정 부분의 어셈블리 코드를 출력할 수 있도록 해준다.
1.
특정 함수의 어셈블리 코드를 출력:
phpCopy code
disassemble -n <함수명>
Plain Text
복사
예를 들어, main 함수의 어셈블리 코드를 출력하려면 다음을 사용:
cssCopy code
disassemble -n main
Plain Text
복사
2.
주소 범위 내의 어셈블리 코드를 출력:
phpCopy code
disassemble -s <시작_주소> -e <종료_주소>
Plain Text
복사
예를 들어, 주소 0x100000000에서 0x100000020 사이의 어셈블리 코드를 출력하려면 다음을 사용:
Copy code
disassemble -s 0x100000000 -e 0x100000020
Plain Text
복사
3.
특정 레지스터를 기준으로 어셈블리 코드 출력:
phpCopy code
disassemble -r <레지스터명>
Plain Text
복사
예를 들어, 현재 RIP 레지스터 값 주변의 어셈블리 코드를 출력하려면 다음을 사용:
Copy code
disassemble -r rip
Plain Text
복사
4.
출력 라인 수 지정:
phpCopy code
disassemble -c <라인_수>
Plain Text
복사
예를 들어, 현재 함수에서 10줄의 어셈블리 코드를 출력하려면 다음을 사용:
rCopy code
disassemble -c 10
Plain Text
복사
memory read
해당 명령어는 특정 부분의 메모리를 읽을 수 있도록 해준다. 기본적인 사용 방법은 아래와 같다.
memory read <시작_주소> --size <바이트_수> --count <읽을_회수>
Plain Text
복사
또는 간단하게:
phpCopy code
x/<읽을_회수><포맷><바이트_수> <시작_주소>
Plain Text
복사
포맷 옵션은 다음과 같습니다:
•
x : 16진수
•
d : 10진수
•
u : 부호 없는 10진수
•
o : 8진수
•
b : 2진수
•
f : 부동 소수점
•
a : 주소
•
i : 명령어
•
c : 문자
예를 들어, 주소 0x100000000에서 4바이트를 16진수 형식으로 읽으려면 다음과 같이 입력:
arduinoCopy code
memory read 0x100000000 --size 4 --count 1
Plain Text
복사
또는 간단한 형식으로:
Copy code
x/1xw 0x100000000
Plain Text
복사
여기서 1은 읽을 회수, x는 16진수 형식, w는 4바이트(Word)를 나타낸다. 또한 b (Byte, 1바이트), h (Halfword, 2바이트), g (Giant, 8바이트) 등의 옵션을 사용할 수 있다.
마치며
해당 lldb 명령어들은 42 이너서클을 진행하면서 굉장히 유용하게 사용해왔던 명령어들을 정리한 것들 입니다. 처음 디버거를 접했을 때, 어려워보이는 생각에 배우는 걸 미뤘었는데 하루라도 더 일찍 배웠으면 하는 마음이 드네용 ㅎ