Why should I know this?

오픈소스에서 원하는 코드 쉽게 찾기 (feat. GDB) 본문

Technic

오픈소스에서 원하는 코드 쉽게 찾기 (feat. GDB)

die4taoam 2022. 2. 11. 07:29

오픈소스에서 원하는 코드를 쉽게 찾는 방법을 알아보겠습니다.

 

이번에 찾고자 하는 코드는 gdb에서 특정 함수를 호출할 수 있게 해주는 로직!

 

예를 들면, gdb에서는 다음과 같은 명령을 수행할 수 있습니다

(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
I am 18500
Hello, I'm loaded!!
$1 = (void *) 0x55555555a2d0

위의 명령처럼 target process context에서 특정 함수의 호출이 가능합니다.

예제에서는 dlopen을 통해 so를 로드했고, 그 결과  so의 init에서 출력해주는 메시지를 볼 수 있습니다.

 

 

1. gdb 를 tracing 가능한 형태로 컴파일한다!

m@Hanbum:~/binutils-gdb$ ./configure CFLAGS="-g -pg" CXXFLAGS="-g -pg"
...
m@Hanbum:~/binutils-gdb$ make -j 18

컴파일이 끝난 뒤 mcount라는 심볼이 존재하는지 확인해야 한다.

m@Hanbum:~/binutils-gdb$ objdump -tT gdb/gdb | grep mcount
000000000029166c l     F .text  000000000000001e              bfd_get_symcount
0000000000302a56 l     F .text  000000000000001e              bfd_get_symcount
00000000003f9618 l     F .text  000000000000001e              bfd_get_symcount
000000000059d177 l     F .text  000000000000001e              bfd_get_symcount
00000000008c30e4 l     F .text  000000000000001e              bfd_get_symcount
00000000008c5d18 l     F .text  000000000000001e              bfd_get_symcount
00000000008dc973 l     F .text  000000000000001e              bfd_get_symcount
00000000008dc991 l     F .text  000000000000001e              bfd_get_dynamic_symcount
00000000008e21d2 l     F .text  000000000000001e              bfd_get_symcount
00000000008e21f0 l     F .text  000000000000001e              bfd_get_dynamic_symcount
000000000090392e l     F .text  000000000000001e              bfd_get_symcount
00000000009462b3 l     F .text  000000000000001e              bfd_get_symcount
00000000009462d1 l     F .text  000000000000001e              bfd_get_dynamic_symcount
000000000094ba15 l     F .text  000000000000001e              bfd_get_symcount
00000000009607b6 l     F .text  000000000000001e              bfd_get_symcount
0000000000968787 l     F .text  000000000000001e              bfd_get_symcount
000000000096fbf2 l     F .text  000000000000001e              bfd_get_symcount
0000000000982a0d l     F .text  000000000000001e              bfd_get_symcount
000000000098fe0d l     F .text  000000000000001e              bfd_get_symcount
0000000000000000       F *UND*  0000000000000000              mcount@GLIBC_2.2.5
0000000000000000      DF *UND*  0000000000000000 (GLIBC_2.2.5) mcount

mcount@GLIBC_2.2.5 가 보이면 잘 된 겁니다.

 

2. uftrace를 설치한다.

uftrace repo 주소

https://github.com/namhyung/uftrace.git

 

3. uftrace로 gdb 추적 데이터를 만든다.

 

먼저 만들것은 오리지날 데이터

m@Hanbum:~$ uftrace record gdb injector
warning: Found custom handler for signal 6 (Aborted) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 12.0.50.20211223-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from injector...
(gdb) b main
Breakpoint 1 at 0x1210: file /home/m/linux_so_injector/main.c, line 7.
(gdb) r
Starting program: /home/m/injector
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffdf28) at /home/m/linux_so_injector/main.c:7
7       {
(gdb) q
A debugging session is active.

        Inferior 1 [process 19739] will be killed.

Quit anyway? (y or n) y

 

 

종료가 제대로 안되서 ctrl-c 명령으로 강제 종료시켰습니다 (...)

 

이번에 만들 것은 찾고자 하는 명령어를 실행하는 데이터

 

m@Hanbum:~$ uftrace record gdb injector
warning: Found custom handler for signal 6 (Aborted) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 12.0.50.20211223-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from injector...
(gdb) b main
Breakpoint 1 at 0x1210: file /home/m/linux_so_injector/main.c, line 7.
(gdb) r
Starting program: /home/m/injector
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffdf28) at /home/m/linux_so_injector/main.c:7
7       {
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
I am 19800
Hello, I'm loaded!!
$1 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$2 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$3 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$4 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$5 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$6 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$7 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$8 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$9 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$10 = (void *) 0x55555556c840
(gdb) call (void *)dlopen("/home/m/signal-checker.so", 2)
$11 = (void *) 0x55555556c840
(gdb) q
A debugging session is active.

        Inferior 1 [process 19800] will be killed.

Quit anyway? (y or n) y

 

dlopen을 11번 호출했습니다.

 

이제 두 개의 데이터가 생겼을 겁니다.

- uftrace.data     (= 두번째)

- uftrace.data.old (= 첫번째)

 

이 두 데이터를 diff 해봅니다.

m@Hanbum:~$ uftrace report --diff uftrace.data.old -s call
...

-48.400 us    -11.800 us           -11   bpstat_do_actions_1
    -15.800 us     -4.600 us           -11   buffer_grow
     -2.340 ms     -5.700 us           -11   build_address_symbolic
     -2.210 ms     -3.100 us           -11   c_language::print_type
    -75.918 ms    -36.800 us           -11   c_parse
   -115.400 us     -9.800 us           -11   c_parse_state::c_parse_state
   -220.300 us     -6.400 us           -11   c_parse_state::~c_parse_state
     -2.207 ms     -4.600 us           -11   c_print_type
     -2.201 ms    -18.100 us           -11   c_print_type_1
    -24.800 us     -4.000 us           -11   c_textual_element_type
     -6.815 ms    -21.700 us           -11   c_value_print
     -2.845 ms     -5.500 us           -11   c_value_print_inner
     -2.799 ms     -9.500 us           -11   c_value_print_ptr
    -73.587 ms   -129.300 us           -11   c_yyparse
   -515.961 ms     -3.600 us           -11   call_command
    -23.900 us     -7.300 us           -11   charset_for_string_type
     -2.384 ms     -3.500 us           -11   check_frame_language_change
     -1.100 us     -0.900 us           -11   check_thread_signals
     +7.384  s     -7.700 us           -11   cmd_func
     -1.400 us     -1.400 us           -11   cmd_simple_func_eq
     +7.379  s    -13.500 us           -11   command_handler
    -24.600 us     -6.500 us           -11   command_line_append_input_line
     +7.378  s    -11.600 us           -11   command_line_handler
     -3.037 ms     -4.100 us           -11   common_val_print
     -6.100 us     -4.500 us           -11   convert_between_encodings
     -1.000 us     -1.000 us           -11   convert_from_func_ptr_addr_identity

call 수가 11번 차이나는 함수는 한 50개 정도 나오는데요 그 중 일부를 발췌해봤습니다.

 

이제는 노가다를 해야 합니다... 대충 이거다 싶은걸 다 검색해봐야 합니다...

// binutils-gdb/gdb/printcmd.c

1461 /* Same as print, except it doesn't print void results.  */
1462 static void
1463 call_command (const char *exp, int from_tty)
1464 {
1465   print_command_1 (exp, false);
1466 }
1467

...


1318 /* Implementation of the "print" and "call" commands.  */
1319
1320 static void
1321 print_command_1 (const char *args, int voidprint)
1322 {
1323   value_print_options print_opts;
1324
1325   struct value *val = process_print_command_args (args, &print_opts, voidprint);
1326

제가 찾고자 하는 함수의 경우 call_command 로 쉽게 찾을 수 있었습니다!

 

 

이상입니다.

 

'Technic' 카테고리의 다른 글

Git blame으로 C/C++ 코드 첫 머지버전 찾는 미립자팁  (0) 2022.09.21
C에서 TRY-CATCH 구현  (0) 2022.03.14
nox 탐지  (0) 2021.11.02
Runtime에 C/C++ 함수 크기 구하기  (0) 2021.06.02
valgrind 옵션 저장.  (0) 2018.09.29
Comments