#include <stdio.h>#include <stdlib.h>void func4(int a, int b) { printf("sum : %d\n", a + b); }void func3(int a, int b) { return func4(a, b); }void func2(int a, int b) { return func3(a, b); }void func1(int a, int b) { return func2(a, b); }int main(int argc, char *argv[]){int a = atoi(argv[1]);int b = atoi(argv[2]);func1(a, b);return 0;}cs
- STACK 정보 확인하기 (backtrace / bt)
특정 중단점에서 정보를 확인하고자 하려 할때 사용하는 명령어입니다. backtrace 또는 bt를 사용하여 정보를 확인할 수 있습니다. 이 정보는 스택 메모리를 기반으로 표시되게 됩니다. 위 예제 코드를 이용하여 분석을 시작해 보겠습니다. 먼저 중단점을 func4()로 설정하고 입력인자로 1 2를 전달하여 실행합니다. 그 후 backtrace 또는 bt 라는 명령어로 스택의 정보를 확인합니다. 그럼 제일 위에 func4() 함수부터 func4() <- func3() <- func2() <- func1() -< main() 함수 순서로 호출한 스택의 정보가 나타납니다. 여기서 각 #0, #1, .., #4가 앞에서 언급한 프레임이란 단위입니다.
|
좀 더 자세한 정보를 확인하기 위해 backtrace 또는 bt 명령어 뒤에 full을 붙여 실행해 보겠습니다.
(gdb) bt full#0 func4 (a=1, b=2) at example2.c:4No locals.#1 0x00000000004005ad in func3 (a=1, b=2) at example2.c:6No locals.#2 0x00000000004005cc in func2 (a=1, b=2) at example2.c:8No locals.#3 0x00000000004005eb in func1 (a=1, b=2) at example2.c:10No locals.#4 0x0000000000400637 in main (argc=3, argv=0x7fffffffda78) at example2.c:17a = 1b = 2cs
예제 코드는 매우 단순하여 상세한 내용이 보이진 않습니다. 지역변수가 있다면 No locals. 대신 해당 함수의 지역변수를 보여주게됩니다. main() 함수에는 a = 1, b = 2란 값이 있다는 걸 보여주고 있네요.
- 프레임 정보 상세하게 확인하기 (info frame)
중단점 상태에서 각 프레임의 정보를 좀 더 자세히 알고 싶다면 info frame 명령어를 사용합니다.
cs(gdb) bt#0 func4 (a=1, b=2) at example2.c:4#1 0x00000000004005ad in func3 (a=1, b=2) at example2.c:6#2 0x00000000004005cc in func2 (a=1, b=2) at example2.c:8#3 0x00000000004005eb in func1 (a=1, b=2) at example2.c:10#4 0x0000000000400637 in main (argc=3, argv=0x7fffffffda78) at example2.c:17(gdb) info frameStack level 0, frame at 0x7fffffffd910:rip = 0x400574 in func4 (example2.c:4); saved rip = 0x4005adcalled by frame at 0x7fffffffd930source language c.Arglist at 0x7fffffffd900, args: a=1, b=2Locals at 0x7fffffffd900, Previous frame's sp is 0x7fffffffd910Saved registers:rbp at 0x7fffffffd900, rip at 0x7fffffffd908
info frame 명령어는 현재 위치한 frame의 정보를 알 수 있습니다. rip나 args의 정보 이전 프레임의 sp(스택 포인터) 등 다양한 정보들이 있네요, 레지스터나 메모리 주소에 대한 이해가 있다면 좀 더 상세한 분석을 할 수 있습니다. 그럼 다른 프레임의 정보는 어떻게 확인할 수 있을까요? 방법은 간단합니다. 각 프레임별로 번호가 있으니 info frame {frame number} 식으로 명령어를 실행하면 해당 프레임의 정보가 보입니다. main() 함수 즉, 4번 프레임의 정보를 보면 아래와 같습니다.
(gdb) info frame 4Stack frame at 0x7fffffffd9a0:rip = 0x400637 in main (example2.c:17); saved rip = 0x7ffff7a2d830caller of frame at 0x7fffffffd970source language c.Arglist at 0x7fffffffd990, args: argc=3, argv=0x7fffffffda78Locals at 0x7fffffffd990, Previous frame's sp is 0x7fffffffd9a0Saved registers:rbp at 0x7fffffffd990, rip at 0x7fffffffd998(gdb)
위에 나타난 정보들이 어떤 의미인지 정리를 잠깐 하도록 하겠습니다.
Stack frame at 0x7fffffffd9a0
- 현재 스택 프레임의 베이스 주소로 저 주소부터 frame 4가 시작한다고 생각하시면 됩니다.
rip = 0x400637 in main (example2.c:17); saved rip = 0x7ffff7a2d830
- rip address pointer는 해당 프레임에서 실행될 다음 명령(instruction)의 주소 포인터입니다.
이 프레임이 main함수와 연관되어 있음을 확인할 수 있습니다. saved rip는 이전 프레임에서 다음에 실행될 명령 주소입니다.
caller of frame at 0x7fffffffd970
- caller of frame은 현재 프레임을 호출한 프레임을 나타냅니다. 즉 main()함수를 호출한 프레임이 되겠네요.
source language c.
- 이건 쉽죠? C로 작성되었다는 의미입니다.
Arglist at 0x7fffffffd990, args: argc=3, argv=0x7fffffffda78
- 함수의 variable 즉 변수의 시작을 나타내는 위치입니다. 어떤 변수들이 존재하는지는 나중에 알아보고 기본적으로 함수로
전달되는 argument의 정보는 알려주네요.
Locals at 0x7fffffffd990, Previous frame's sp is 0x7fffffffd9a0
- Locals는 지역변수의 시작 위치를 표시해 줍니다. Previous frame's sp는 말 그대로 이전 프레임의 스택포인터를 가리킵니다.
이 방법외에도 각 frame을 이동하는 명령어로 up, down이 있습니다. 프레임을 이동해갈 수 있는 명령어 입니다.
|
cs |
- Stack memory 확인하기 (x/FMT Address)
-
x/o : octal
-
x/x : hex
-
x/d : decimal
-
x/u : unsigned decimal
-
x/t : binary
-
x/ f : float
-
x/a : address
-
x/i : instruction
-
x/c : char
-
x/s : string
-
x/z : hex, zero padded on the left
(gdb) x/8x 0x7fffffffd9100x7fffffffd910: 0x05ffda98 0x00000000 0x00000002 0x000000010x7fffffffd920: 0xffffd940 0x00007fff 0x004005cc 0x00000000(gdb) x/8o 0x7fffffffd9100x7fffffffd910: 0577755230 0 02 010x7fffffffd920: 037777754500 077777 020002714 0(gdb) x/8c 0x7fffffffd9100x7fffffffd910: -104 '\230' -38 '\332' -1 '\377' 5 '\005' 0 '\000' 0 '\000' 0 '\000' 0 '\000'(gdb) x/8s 0x7fffffffd9100x7fffffffd910: "\230\332\377\005"0x7fffffffd915: ""0x7fffffffd916: ""0x7fffffffd917: ""0x7fffffffd918: "\002"0x7fffffffd91a: ""0x7fffffffd91b: ""0x7fffffffd91c: "\001"(gdb) x/8d 0x7fffffffd9100x7fffffffd910: -104 -38 -1 5 0 0 0 0(gdb) x/8t 0x7fffffffd9100x7fffffffd910: 10011000 11011010 11111111 00000101 00000000 00000000 00000000 00000000(gdb) x/8f 0x7fffffffd9100x7fffffffd910: 4.9729545178123994e-316 2.1219957919534036e-3140x7fffffffd920: 6.9533558073448912e-310 2.0729947080329522e-3170x7fffffffd930: 6.9533558073488437e-310 2.1219957919534036e-3140x7fffffffd940: 6.9533558073464722e-310 2.0730100240679732e-317(gdb) x/8a 0x7fffffffd9100x7fffffffd910: 0x5ffda98 0x1000000020x7fffffffd920: 0x7fffffffd940 0x4005cc <func2+29>0x7fffffffd930: 0x7fffffffd990 0x1000000020x7fffffffd940: 0x7fffffffd960 0x4005eb <func1+29>(gdb) x/8i 0x7fffffffd9100x7fffffffd910: cwtl0x7fffffffd911: (bad)0x7fffffffd913: add $0x0,%eax0x7fffffffd918: add (%rax),%al0x7fffffffd91a: add %al,(%rax)0x7fffffffd91c: add %eax,(%rax)0x7fffffffd91e: add %al,(%rax)0x7fffffffd920: rex fcos(gdb) x/8z 0x7fffffffd9100x7fffffffd910: 0x0000000005ffda98 0x00000001000000020x7fffffffd920: 0x00007fffffffd940 0x00000000004005cc0x7fffffffd930: 0x00007fffffffd990 0x00000001000000020x7fffffffd940: 0x00007fffffffd960 0x00000000004005ebcs
위와 같이 출력함으로써 스택프레임에서 스택의 정보를 더 얻을 수 있습니다. 분석 능력만 갖추고 있다면 info frame 명령어를 이용해서 굉장히 많은 정보를 얻을 수 있을 거에요!
[GDB]
2018/08/13 - [Linux/Debugging & Testing] - [gdb] The GNU Debugger : 1. Introduction
2018/08/14 - [Linux/Debugging & Testing] - [gdb] The GNU Debugger : 2. 중단점 설정하기
'Linux > Debugging & Testing' 카테고리의 다른 글
[ELF] ELF Header (0) | 2018.08.27 |
---|---|
[커널분석] Architecture 별 분석을 위한 설정 (ctags & cscope) (0) | 2018.08.21 |
[gdb] The GNU Debugger : 2. 중단점 설정하기 (0) | 2018.08.14 |
[gdb] The GNU Debugger : 1. Introduction (2) | 2018.08.13 |
[SOLVE] valgrind: failed to start tool 'memcheck' for platform... ': No such file or directory (0) | 2018.07.27 |