문제

나는 같은 도구를 찾고 있습니다 ltrace 또는 스트라스 이는 실행 파일에서 로컬로 정의 된 기능을 추적 할 수 있습니다. LTRACE는 동적 라이브러리 호출 만 추적하고 Strace는 시스템 호출을 추적합니다. 예를 들어 다음 C 프로그램이 주어지면

#include <stdio.h>

int triple ( int x )
{
  return 3 * x;
}

int main (void)
{
  printf("%d\n", triple(10));
  return 0;
}

프로그램을 실행합니다 ltrace 전화를 표시합니다 printf 그것은 표준 라이브러리 기능 (내 시스템의 동적 라이브러리)이므로 strace 시작 코드, Printf 구현에 사용되는 시스템 호출 및 종료 코드에서 모든 시스템 호출을 표시하지만 기능을 보여줄 무언가를 원합니다. triple 부름 받았다. 로컬 함수가 최적화 컴파일러에 의해 인쇄되지 않았고 바이너리가 제거되지 않았다고 가정하면 (심볼이 제거됨),이를 수행 할 수있는 도구가 있습니까?

편집하다

몇 가지 설명 :

  • 도구가 비 국소 함수에 대한 추적 정보도 제공해도 괜찮습니다.
  • 특정 도구를 지원하여 프로그램을 다시 컴파일하고 싶지 않으므로 실행 파일의 기호 정보로 충분해야합니다.
  • LTRACE/Strace와 같이 도구를 사용하여 기존 프로세스에 연결할 수 있다면 정말 좋을 것입니다.
도움이 되었습니까?

해결책

특정 기능에 대해서만 통보 받기를 원한다고 가정하면 다음과 같이 할 수 있습니다.

디버그 정보로 컴파일합니다 (이미 심볼 정보가 있으므로 디버그가 충분할 것입니다).

주어진

#include <iostream>

int fac(int n) {
    if(n == 0)
        return 1;
    return n * fac(n-1);
}

int main()
{
    for(int i=0;i<4;i++)
        std::cout << fac(i) << std::endl;
}

GDB를 사용하여 추적하십시오.

[js@HOST2 cpp]$ g++ -g3 test.cpp
[js@HOST2 cpp]$ gdb ./a.out
(gdb) b fac
Breakpoint 1 at 0x804866a: file test.cpp, line 4.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>silent
>bt 1
>c
>end
(gdb) run
Starting program: /home/js/cpp/a.out
#0  fac (n=0) at test.cpp:4
1
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
1
#0  fac (n=2) at test.cpp:4
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
2
#0  fac (n=3) at test.cpp:4
#0  fac (n=2) at test.cpp:4
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
6

Program exited normally.
(gdb)

다음은 모든 기능의 주소를 수집하기 위해하는 일입니다.

tmp=$(mktemp)
readelf -s ./a.out | gawk '
{ 
  if($4 == "FUNC" && $2 != 0) { 
    print "# code for " $NF; 
    print "b *0x" $2; 
    print "commands"; 
    print "silent"; 
    print "bt 1"; 
    print "c"; 
    print "end"; 
    print ""; 
  } 
}' > $tmp; 
gdb --command=$tmp ./a.out; 
rm -f $tmp

현재 프레임을 인쇄하는 대신 (bt 1), 당신은 당신이 좋아하는 모든 것을 할 수 있고, 전 세계의 가치를 인쇄하거나, 일부 쉘 명령을 실행하거나, 무언가를 누르면 무언가를 우편으로 할 수 있습니다. fatal_bomb_exploded 기능 :) 슬프게도, GCC는 그 사이의 일부 "현재 언어 변경"메시지를 출력합니다. 그러나 그것은 쉽게 철회됩니다. 큰 문제는 없습니다.

다른 팁

시스템 탭 최신 Linux 상자 (Fedora 10, Rhel 5 등)에 사용할 수 있습니다.

먼저 다운로드 para-callgraph.stp 스크립트.

그런 다음 실행 :

$ sudo stap para-callgraph.stp 'process("/bin/ls").function("*")' -c /bin/ls
0    ls(12631):->main argc=0x1 argv=0x7fff1ec3b038
276  ls(12631): ->human_options spec=0x0 opts=0x61a28c block_size=0x61a290
365  ls(12631): <-human_options return=0x0
496  ls(12631): ->clone_quoting_options o=0x0
657  ls(12631):  ->xmemdup p=0x61a600 s=0x28
815  ls(12631):   ->xmalloc n=0x28
908  ls(12631):   <-xmalloc return=0x1efe540
950  ls(12631):  <-xmemdup return=0x1efe540
990  ls(12631): <-clone_quoting_options return=0x1efe540
1030 ls(12631): ->get_quoting_style o=0x1efe540

또한보십시오: SystemTap 및 Oprofile 업데이트를 관찰하십시오

사용 errobes (Linux 3.5 이후)

모든 기능을 추적하고 싶다고 가정합니다 ~/Desktop/datalog-2.2/datalog 매개 변수로 호출 할 때 -l ~/Desktop/datalog-2.2/add.lua ~/Desktop/datalog-2.2/test.dl

  1. cd /usr/src/linux-`uname -r`/tools/perf
  2. for i in `./perf probe -F -x ~/Desktop/datalog-2.2/datalog`; do sudo ./perf probe -x ~/Desktop/datalog-2.2/datalog $i; done
  3. sudo ./perf record -agR $(for j in $(sudo ./perf probe -l | cut -d' ' -f3); do echo "-e $j"; done) ~/Desktop/datalog-2.2/datalog -l ~/Desktop/datalog-2.2/add.lua ~/Desktop/datalog-2.2/test.dl
  4. sudo ./perf report -G

list of functions in datalog binary call tree when selecting dl_pushlstring, showing how main called loadfile called dl_load called program called rule which called literal which in turn called other functions that ended up calling dl_pushlstring, scan (parent: program, that is, the third scan from the top) which called dl_pushstring and so on

GCC 옵션으로 추적하려는 코드를 다시 컴파일 할 수 있다고 가정합니다. -finstrument-functions, 당신이 사용할 수있는 에트레이스 함수를 얻으려면 그래프를 호출합니다.

출력의 모습은 다음과 같습니다.

\-- main
|   \-- Crumble_make_apple_crumble
|   |   \-- Crumble_buy_stuff
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   \-- Crumble_prepare_apples
|   |   |   \-- Crumble_skin_and_dice
|   |   \-- Crumble_mix
|   |   \-- Crumble_finalize
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_put
|   |   \-- Crumble_cook
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_bake

Solaris에서 Truss (Strace Equivalent)는 라이브러리를 추적 할 수있는 능력을 가지고 있습니다. Strace에 그런 능력이 없다는 것을 알게되면 놀랐습니다.

$ sudo yum install frysk
$ ftrace -sym:'*' -- ./a.out

더: ftrace.1

해당 기능을 외부 라이브러리로 외부화하는 경우 (LTRACE와 함께) 호출되는 것을 볼 수 있어야합니다.

이것이 작동하는 이유는 ltrace가 앱과 라이브러리 사이에 자체적으로 참여하고 모든 코드가 하나의 파일로 내재화되면 통화를 가로 채울 수 없기 때문입니다.

IE : ltrace xterm

X 라이브러리에서 물건을 뿌리고 X는 거의 시스템이 아닙니다.

이 외부에서는이를 수행하는 유일한 방법은 Prof 플래그 또는 디버그 기호를 통한 컴파일 타임 절편입니다.

방금이 앱을 뛰어 넘었는데 흥미로워 보입니다.

http://www.gnu.org/software/cflow/

그러나 나는 그것이 당신이 원하는 것을 생각하지 않습니다.

함수가 손상되지 않으면 운이 좋을 수도 있습니다. objdump -d <program>.

예를 들어, GCC 4.3.2의 시작 부분에 전리품을 가져 가겠습니다. main 루틴:

$ objdump `which gcc` -d | grep '\(call\|main\)' 

08053270 <main>:
8053270:    8d 4c 24 04             lea    0x4(%esp),%ecx
--
8053299:    89 1c 24                mov    %ebx,(%esp)
805329c:    e8 8f 60 ff ff          call   8049330 <strlen@plt>
80532a1:    8d 04 03                lea    (%ebx,%eax,1),%eax
--
80532cf:    89 04 24                mov    %eax,(%esp)
80532d2:    e8 b9 c9 00 00          call   805fc90 <xmalloc_set_program_name>
80532d7:    8b 5d 9c                mov    0xffffff9c(%ebp),%ebx
--
80532e4:    89 04 24                mov    %eax,(%esp)
80532e7:    e8 b4 a7 00 00          call   805daa0 <expandargv>
80532ec:    8b 55 9c                mov    0xffffff9c(%ebp),%edx
--
8053302:    89 0c 24                mov    %ecx,(%esp)
8053305:    e8 d6 2a 00 00          call   8055de0 <prune_options>
805330a:    e8 71 ac 00 00          call   805df80 <unlock_std_streams>
805330f:    e8 4c 2f 00 00          call   8056260 <gcc_init_libintl>
8053314:    c7 44 24 04 01 00 00    movl   $0x1,0x4(%esp)
--
805331c:    c7 04 24 02 00 00 00    movl   $0x2,(%esp)
8053323:    e8 78 5e ff ff          call   80491a0 <signal@plt>
8053328:    83 e8 01                sub    $0x1,%eax

모든 어셈블러를 통해 약간의 노력이 필요하지만 주어진 기능에서 가능한 모든 호출을 볼 수 있습니다. 사용하기 쉽지 않습니다 gprof 또는 언급 된 다른 유틸리티 중 일부는 몇 가지 뚜렷한 장점이 있습니다.

  • 일반적으로 사용하려면 응용 프로그램을 다시 컴파일 할 필요가 없습니다.
  • 가능한 모든 기능 호출을 표시하는 반면 gprof 실행 된 기능 호출 만 표시합니다.

GDB로 추적 함수 호출을 자동화하기위한 쉘 스크립트가 있습니다. 그러나 실행 프로세스에 첨부 할 수는 없습니다.

blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/

페이지 사본 - http://web.archive.org/web/20090317091725/http://blog.superadditive.com/2007/12/01/call-graphs-using-the-gnu-project-debugger/

도구 사본 -Callgraph.tar.gz

http://web.archive.org/web/20090317091725/http://superadditive.com/software/callgraph.tar.gz

프로그램에서 모든 함수를 덤프하고 각 함수에서 중단 점으로 GDB 명령 파일을 생성합니다. 각 중단 점에서 "Backtrace 2"및 "Contoint"가 실행됩니다.

이 스크립트는 큰 porject (~ 수천 개의 함수)에서는 다소 느리므로 기능 목록에 필터를 추가합니다 (EGREP를 통해). 매우 쉬웠 으며이 스크립트를 거의 Evry Day를 사용합니다.

GPROF 당신이 원하는 것일 수 있습니다

Linux C/C ++ 응용 프로그램의 추적 프레임 워크 인 Traces를 참조하십시오.https://github.com/baruch/traces#readme

코드를 인스트루먼트로 다시 컴파일해야하지만 모든 기능, 매개 변수 및 리턴 값의 목록을 제공합니다. 대형 데이터 샘플을 쉽게 탐색 할 수있는 대화식이 있습니다.

Kcachegrind

https://kcachegrind.github.io/html/home.html

테스트 프로그램 :

int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }

int main(int argc, char **argv) {
    int (*f)(int);
    f0(1);
    f1(1);
    f = pointed;
    if (argc == 1)
        f(1);
    if (argc == 2)
        not_called(1);
    return 0;
}

용법:

sudo apt-get install -y kcachegrind valgrind

# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c

# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main

# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

당신은 이제 많은 흥미로운 성능 데이터를 포함하는 멋진 GUI 프로그램 안에 남아 있습니다.

오른쪽 하단에서 "Call Graph"탭을 선택하십시오. 이것은 함수를 클릭 할 때 다른 Windows의 성능 메트릭과 관련된 대화식 통화 그래프를 보여줍니다.

그래프를 내보내려면 마우스 오른쪽 버튼을 클릭하고 "그래프 내보내기"를 선택하십시오. 내보낸 PNG는 다음과 같습니다.

그로부터 우리는 그것을 볼 수 있습니다.

  • 루트 노드는입니다 _start, 실제 ELF 진입 지점이며 GLIBC 초기화 보일러 플레이트가 포함되어 있습니다.
  • f0, f1 그리고 f2 서로 예상대로 호출됩니다
  • pointed 기능 포인터로 호출했지만 표시됩니다. 우리가 명령 줄 인수를 통과 한 경우에 전화되지 않았을 수도 있습니다.
  • not_called 우리는 추가 명령 줄 인수를 통과하지 못했기 때문에 달리기에서 호출되지 않았기 때문에 표시되지 않습니다.

멋진 것 valgrind 특별한 컴파일 옵션이 필요하지 않습니다.

따라서 소스 코드가없고 실행 파일 만 있으면 사용할 수 있습니다.

valgrind 경량 "가상 머신"을 통해 코드를 실행하여이를 수행합니다.

우분투 18.04에서 테스트.

바라건대 Callgrind 또는 Cachegrind 도구 ~을 위한 Valgrind 당신이 원하는 정보를 줄 것입니다.

참고 : 이것은 Linux 커널 기반 FTRACE가 아니라 최근 로컬 기능 추적 및 제어 흐름을 달성하도록 설계된 도구입니다. Linux ELF X86_64/X86_32는 공개적으로 지원됩니다.

https://github.com/leviathansecurity/ftrace

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top