Skip to content

Instantly share code, notes, and snippets.

@claudiajkang
Last active November 8, 2018 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save claudiajkang/04b95dfa84f3a936a3b4549327f4bcb5 to your computer and use it in GitHub Desktop.
Save claudiajkang/04b95dfa84f3a936a3b4549327f4bcb5 to your computer and use it in GitHub Desktop.
uftrace

물 흘러가듯이 치는 것 부터!

  • [add / commit / push] - [tutorial v2]

  • [rebase / blame] - [tutorial v3]

  • branch : 같은 폴더 다른 세상인 것처럼 운영이 되는 개념이 중요

  • rebase interactive

  • pull -> 바로 merge -> conflict 가능성 있음.

  • fetch -> 바로 merge 안하고, .git에 저장

  • fetch -> rebase -> rewind : rebase시, undo 공간.

  • Git 상태확인 명령어
$ git shortlog
$ git diff
$ git commit -sm "commit meesage" # s옵션은 서명 포함
$ git commit --amend # 가 장 위에 있는 commit 을 수정
$ git reset # reset 으로 add 한거 취소
$ git merge test # 현재 브랜치랑 test 브랜치랑 합치기
$ git rebase -i --root # commit 최초 기록부터 리베이스
$ git rebase --continue # rebase 계속
$ git blame report_card.c # 어떤 가 파일이든 누 어느라인을 수정했는지 파악

1) 실습

  • install시, tip. make -j 옵션 사용.
  • compile시, pg옵션 필수 !!
    • g : binary에 debug information 추가
    • pg : 모든 function 첫 시작 부분에 mcount를 호출하도록. (mocunt는 libc에 존재 -> mcount를 후킹애서 사용)
  • uftrace/wiki/tutorial
  • OSS-tutorial : uftrace.data.printf_kern에 들어가서 $ uftrace replay # -D 옵션으로 depth 조정 가능 or $ uftrace info or $ uftrace report # -s 옵션 : 해당 func가 실제 소비한 시간 or $ uftrace graph # call count 확인 가능 해보기.
  • kern / xen 이 서로 다름.
  • [--auto-args 옵션] $ gcc print.c -o print -pg -O0 -g -> $ uftrace --auto-args print_var
    • O0 : compiler optimization
  • [graph 옵션] : 동일하게 실행되는 함수를 묶어서 보여줌.
  • [tui 옵션] : configure에서 확인한 lib에서 TUI 관련 lib 설치 필요 $ sudo yum install ncurses-devel # fedora
  • run test : $ uftrace/test/.runtest.py <args>
  • coredump : $ gdb <coredump 파일> | $ uftrace <coredump??> : crash point 확인 가능.

2) 사용사례

  • 코드 실행 시간 확인
  • 함수 동작원리 없이 어떻게 동작하는지 분석하고 싶을 때

1. Git/Github 팀(3명)실습 README에 각자 PR로 이름적기 등

  • git pull vs git fetch

2. uftrace python script 사용법과 원리 이해

## 3. 간략한 uftrace 내부원리 이해와 소스 중간중간 prinf() 찍어보기 (-vvv 활용법)

## 4. 내가 집중할(기여할) 영역 찾아보기, 기여할 idea 고민/토론 1

  • #1 터미널 : 잘써야됨.
  • git patch
$ git commit --amend
$ git apply ~/where/to/*.patch # git apply 는 "모두 적용, 아니면 모두 취소" 모델을 사용
$ git format-patch -1 -o /where/you/want # 패치 파일 생성시 
$ git send-email --annotate --cover-letter --to climbbb.kim@gmail.com *.patch 
$ git send-email --to-cmd ./scripts/get_maintainer.pl /where/to/*.patch

관심 있는 분야에 대한 메일링 리스트 보기

  • git am

  • commit message : 해당 파일에 대한 history 참고

  • RFC : Request For Comment

    이 부분을 커밋 했는데 확신이 안설 때.. PR? 패치? 보낼 때 내용 추가

  • 리눅스 커널 패치하기 (이거 찾아보면 됨)

  • git commit -s : signed-off-by 옵션이 바로 붙음

  • coding rule 확인 필요.

    ex) 커널의 경우 if(1) -> if (1)

  • 소스 패치는 해당 서브 메일링 리스트에다가 보냄. (주로 커널에 보내지 않음)

  • udev 같은 system programming 하고 kernel로 오는걸 추천.

    초심자를 위한 staging 폴더 존재.

  • kernel 소스를 분석할 때 길을 잃지 말 것 # 해당 함수가 무엇이든 그냥 일단 스킵하고 전체 뼈대 이해 먼저

  • insmod / rmmod

    insmod 사용 시 파라미터 값을 넘겨줄 수 있음 파라미터 값은 /sys/module/<module명> ... 여기로 가면 파라미터 값 확인 가능

  • debugfs : 디버깅 시 사용

  • jazzguitar81/koss 실습 시, debug fs 옵션 on 필요.

    난이도 : simple < workerqueue < usbchecker < yavta

  • 시스템 프로그래밍 + uftrace 를 통해 커널 일부의 구조 파악 가능

2. Kernel

  • uftrace

    1. userspace
    2. kernel
    3. library
  • uftrace tracing 실습

#include <stdio.h>

int main()
{
  printf("hello\n");
  flush(stdout);
}

$ touch a

$ sudo uftrace record --force -K 20 rm -f a

$ sudo uftrace replay

3. uftrace python script

  1. 함수 시작 시 기록.
  2. 함수 엔트리 증가.
  3. 함수 종료시 엔트리 삭제.
  4. 함수 종료.

-> 파이썬을 통해서 uftrace 진행

import sys
count = 0

def uftrace_begin(args):
 print "begin"
 print sys.platform
 
def uftrace_entry(args):
 global count
 count += 1

def uftrace_exit(args):
 pass
 
def uftrace_End():
 print("{} called ".format(count))
// fibonacci
#include <stdio.h>
int main()
{
     int n = 20;
     long i, a=0, b=1;

     for ( i=1; i < n; i++) {
         a+=b;
         b=a-b;
     }

     printf("%lu\n", a);
}
// fibonacci_recursive
 
#include <stdio.h>
int fibonacci(int);
 
int main()
{
     int n = 20 i, result;

     for ( i=1; i < n; i++) {
         result=fibonacci(i)
     }

     printf("%lu\n", result);
     return 0;
}
 
int fibonacci(int n)
{
     if(n == 0 || n == 1)
         return n;
     else
         return fibonacci(n-1) + fibonacci(n-2);
}
 
  • 컴파일 방법

$gcc p1.c -o p1 -pg -g

man uftrace script 참고

  • 예제 : uftrace/scripts/*.py

$ uftrace record --auto-args p1 $ uftrace record -S scripts/count.py --auto-args p1

  • fitler 기능 사용

외부 어플리케이션 모니터링 프로그램

2. uftrace - 전체적인 부분 (OSS Sumit 자료 마지막 부분 참고)

3. gcc -pg vs -g option difference

4. uftrace 호출 흐름

함수 호출 규약

uftrace파일을 실행한 이후 misc/debug.sh의 내부 실행 주소를 바꾼 후 실행하면 실제 gdb로 디버깅할때와는 달리 함수 호출 부분에 uftrace로 함수 호출 순서가 바뀌는 것을 볼 수 있음.

  • uftrace/arch/x86_64/mount.S에서 함수 리턴 주소를 스택에 쌓고 새로운 리턴 주소로 바꾼 후, 함수 실행 : 리턴 값 파싱 + 복구 역할 -> 리턴이 될 때(mcount_return) uftrace가 알아차릴 수 있음.

-> uftrace는 아래에서 설명하는 예제에서 두 번째 함수 호출시 원래 함수로 가야하는 주소를 GOT에서 이미 알고 있는데도 불구하고 uftrace 내의 로직에서 첫 번째 함수 호출 시에 실행했던 linking 과정의 값으로 복구해놈. -> plt_hooker 사용. --> uftrace가 두 번재 함수의 경우에도 linking을 다시하도록 복구함!

5. System 함수 디버깅

  • PLT(Procedure Linking Table) / GOT(Global Offset Table) / Dynamic Linking / lazy binding

  • GOT : 프로세스가 가지고 있는 지도 or 이정표

  • lazy binding은 운영체제마다 실행되는 함수나 과정이 다름!

  • ex)getpid debugging (assembler code) -> 리눅스의 경우 lazy binding(binary를 실행할 때 모든 바이너리를 linking해줌). but windows는 그렇지 않음.

// 예제 소스
void main()
{
  getpid();
  getpid();
 }
// 디버깅 시에는 첫 getpid 랑 두번째 getpid가 불리는 과정이 다른 것을 확실히 알아야됨. 
// plt -> 아래 세 가지의 라인으로 구성. (링킹 되기 전과 후가 다름) 
(gdb) disas getpid
Dump of assembler code for function getpid@plt:
0x00000000004004b0 <+0>:     jmpq   *0x200b62(%rip)      # 0x601018(got주소)    # plt+0의 경우 뭐가 됬든 실행 -> 601018에 있는 값으로 실행하라. (처음과 두번째에서 0x601018의 값이 다를것!!!!!)
0x00000000004004b6 <+6>:     pushq  $0x0            # 처음에는 무조건 plt+0 plt+6으로 점프함. 왜냐면 #0x601018이라는 값에 plt+6 주소가 들어가 있음.
0x00000000004004bb <+11>:    jmpq   0x4004a0        # -> 링킹으로 넘어가기  과정. 


// process 매핑 맵을 가져다 줌. 
(gdb) info proc mapping
원래 함수 어드레스가 libc-2.27.so의 주소에 매핑되어있는 것을 확인할  있음.
// 최종 


(gdb) disass main
Dump of assembler code for function main:
0x0000000000400652 <+0>:     push   %rbp
0x0000000000400653 <+1>:     mov    %rsp,%rbp
0x0000000000400656 <+4>:     sub    $0x10,%rsp
0x000000000040065a <+8>:     callq  0x4004d0 <mcount@plt>
0x000000000040065f <+13>:    movl   $0x0,-0x4(%rbp)
0x0000000000400666 <+20>:    mov    $0x0,%eax
=> 0x000000000040066b <+25>:    callq  0x4004b0 <getpid@plt>
0x0000000000400670 <+30>:    mov    $0x0,%eax
0x0000000000400675 <+35>:    callq  0x4004b0 <getpid@plt>
0x000000000040067a <+40>:    mov    $0x0,%eax
0x000000000040067f <+45>:    leaveq
0x0000000000400680 <+46>:    retq
End of assembler dump.
(gdb) si
0x00000000004004b0 in getpid@plt ()
(gdb) disas
Dump of assembler code for function getpid@plt:
=> 0x00000000004004b0 <+0>:     jmpq   *0x200b62(%rip)        # 0x601018
0x00000000004004b6 <+6>:     pushq  $0x0
0x00000000004004bb <+11>:    jmpq   0x4004a0
End of assembler dump.
(gdb) x/gx 0x601018
0x601018:       0x00000000004004b6
(gdb) c
Continuing.
Breakpoint 2, 0x0000000000400675 in main ()
(gdb) disas
Dump of assembler code for function main:
0x0000000000400652 <+0>:     push   %rbp
0x0000000000400653 <+1>:     mov    %rsp,%rbp
0x0000000000400656 <+4>:     sub    $0x10,%rsp
0x000000000040065a <+8>:     callq  0x4004d0 <mcount@plt>
0x000000000040065f <+13>:    movl   $0x0,-0x4(%rbp)
0x0000000000400666 <+20>:    mov    $0x0,%eax
0x000000000040066b <+25>:    callq  0x4004b0 <getpid@plt>
0x0000000000400670 <+30>:    mov    $0x0,%eax
=> 0x0000000000400675 <+35>:    callq  0x4004b0 <getpid@plt>
0x000000000040067a <+40>:    mov    $0x0,%eax
0x000000000040067f <+45>:    leaveq
0x0000000000400680 <+46>:    retq
End of assembler dump.
(gdb) x/gx 0x601018
0x601018:       0x00007ffff7ade720

Q. 왜 0x601018일까?

(gdb) si
0x00000000004004b0 in getpid@plt ()
(gdb) disass
Dump of assembler code for function getpid@plt:
=> 0x00000000004004b0 <+0>:     jmpq   *0x200b62(%rip)        # 0x601018
0x00000000004004b6 <+6>:     pushq  $0x0
0x00000000004004bb <+11>:    jmpq   0x4004a0
End of assembler dump.
(gdb) info reg $rip
rip            0x4004b0 0x4004b0 <getpid@plt>
(gdb) x/gx $rip+0x200b62
0x601012:       0x04b600007ffff7de
(gdb) x/gx $rip+0x200b62+6
0x601018:       0x00000000004004b6

1. 집중할 컨트리뷰션 작업 계획 마무리 (각자 집중할 부분까지)

엑셀에 미리 적어놓고 하기! -> 각자 보물캐기 하듯이 하기 [ wants | needs ] patch needs > wants 패치하기

  • 컨트리뷰션 종류: test, doc(예제, 설명 추가), bugfix, refactoring, 이슈, 이슈 댓글, PR, PR 댓글 등

  • 집중할 작업 종류

  1. dwarf 기능 : debug format 기능 | 불안정 | 채워넣어야 될 부분 많음 2) TUI 기능
  2. script 기능 : ex) malloc, free

1) ~ 3) : 추가 된지 얼마 안됨. 핫한 기능. 보안 여지 필요.

  1. dump, info 기능
  2. recv 기능
  3. report 기능
  4. replay 기능
  5. graph 기능
  6. event 관련
  7. trigger, filter (count, at return, 등)

2. uftrace 관련 스터디 (ELF, PLT/GOT, Calling convention 등)

3. uftrace Internals (주요로직 소스분석, 이해, 원하는 로직, 소스 분석)

1. Before

A.

Team1

$ uftrace replay -A fib@n tests/t-fibonacci 5

-> 이 경우는 gcc -g옵션으로 디버깅 옵션으로 빌드하기

-> value filter 시 적용 가능할듯.

B.Dwarf

어디서부터 시작해야할지? -> Compiler 별로 포맷도 다르고 형태도 다름.

dwarfview를 바탕으로.

dwarf: 컴파일된 소스를 저장

-> uftrace 는 function을 중점으로 생각...

-> dwarf 표준 문서 참고 : dwarf 2 표준 문서 추천

-> concept 이해 -> 문서보기

-> example 기준으로 확인해보기.

C. Libelf

구현이 달라졌을 때 동일한 인터페이스를 쓸 수 있게.

elf 코드 쓰는 쪽/ elf코드 안 쓰는 쪽

endian / machine 크기 변경 시 발생하는 문제................고민 필요.

D. Code coverage

code coverage 확인 필요......

F. Dynamic Linking

plt[0] : loader의 주소가 있음

pg opt 없이 시작 -> mcount option 을 메모리의 다른 영역에 저장 ->

got table의 0번에 링커 대신 uftrace libmcount.so 주소로 강제 변경 -> libmcount.so로 가서 plthook이 가능하게...

opcode / operand 차이 유지가 필요

  • gcc 는 함수 호출 규약을 깨는 경우가 많음..................

  • 규약을 깬다? callee caller 부분의 로직을 강제로 깸

  • gcc 는 컴파일을 3번 컴파일............... <*>

  • instruction decoding 필요

    1. 컴파일러가 지원이 없어도 NOP으로 바꿔서 하는 방안
    1. 컴파일 옵션 없이 코드 삽입 후 mcount 부를 수 있게
    1. attach를 해서 붙어서 확인 (attach를 제대로 쓰려면 dynamic tracing 필요)

-> 컴파일 작업 없이 tracing이 가능

-> decoding -> 캡스톤 ? 을 사용할 예정.......

2. Details of uftrace's TODO

wiki's TODO filter는 record / runtime 모두 사용 가능

커널 기능에서 좋은 걸 user에서 쓸 수 있었으면 좋겠다 -> uftrace 개발 시작 (C/C++지원, 차차 python 진행 예정)

- cleanup task management
- more trigger action
- trigger filtering (ignore, count, at return, ...)
- improve documentation
- report w/ multi-thread
- config file support
- filter by argument value
- filter by function size
- filter by source location
- filter by caller(?)
- SDT argument support
- LTT-ng event (tracepoint) support
- symbol file compression
- reading/watching external data (global variable, cpu, ...)
- show kernel function argument and return value (with kprobes)
- different clock support (TSC on x86, ...)
- generic field support for report
- field and sort support for TUI
- filtering on TUI
- replay on TUI
- python 3 support
- python function tracing
- write useful script examples
- dynamic tracing support
- attach to existing process
- signal trigger support (for daemons)
- process and display multiple data together
- graph diff support
- full demangling support
  1. Cleanup task management : struct uftrace_task(open_data_file) / struct ftrace_task_handle(file 데이터 관련) - Finding session에 필요 => 두 개 data 구조체를 하나로 만드려고 함 (내부 구현 작업 필요)

  2. More trigger actions : Read/Watch/Counting/Ignoring(trigger를 동작하게 되면 영원이 동작하게 되는데 일시적으로 다운 가능하게)/.. 구현 O -> 더 좋은 것이 있는지 고민 필요...

  3. Improve documentation, github.io랑 wiki

  4. Report with multi-thread : 쭉 파싱해서 통계 내는 Report 기능을 multi-thread로 동작하면 빨리 처리할 수 있지 않을까

  5. Value filter : 값에 따른 필터 -> $ uftrace -V 'foo@arg1>0' foobar -> $ uftrace -V 'foo@arag1/s=="XXX"' foobar

  6. Size filter : $ uftrace -Z 16 foobar

  7. Location filter : 특정 dir 내의 파일만 필터, 무시 - $ uftrace -O src/foo foobar or $ uftrace -O !^tests/ foobar

  8. Caller filter -> 구현 완료 : 특정 function 호출 과정에 대한 필터 $ uftrace -C malloc foobar 소스코드만 보고 호출 로직이 이해가 안될 때 이걸 사용하면 좋음.

  9. SDT argument support : 커널 SDTv3 allows argument가 필요.

ubuntu 기준 project는 SDTv3가 적용되어 있다.

  1. LTT-ng event support : 시스템 전체 트레이스를 할 수 있는 LTT-ng 프로젝트를 적용 하는 것

  2. Symbol file compression : symbol 파일을 text로 저장하는데 압축하면 조금 이득이 되지 않을까. 현재는 function에 대해서만 symbol table 저장 중.

  3. Watch point -> 구현 완료 : 값이 바뀔때 보여줄 수 있도록. 현재는 cpu만 가능.

  4. Kernel function argument : Kernel function은 argument가 저장 x => kprobe로 사용하면 될듯...... kprobe가 저장이 되고 function 내용이 저장이 되어야 하는데, interrupt 발생 시 문제 발생가능성 존재

  5. Differenct clock support : clock_gettime(시스템 콜) 사용하면 -> 커널까지 갔다와야하니까 오래 걸릴 가능성 존재함.

    • 해결 할려면 x86은 tsc를 사용하면 됨. but 이건 다른 clock이랑 호환이 안됨 => 시간을 정확히 측정할 수 없음
  6. Report field

  • Total time, self time, call
  • Avg total, min total, max total
  • Avg self, min self, max self => 원하는대로 골라서 했으면 좋겠다.
  1. TUI Update
  • Filter change
  • Field change
  • Sort support (for report)
  • open/close data
  • Replay (with folding) -> 지원 x , folding 구현이 어려움
  1. Python update : python2/3를 지원할 수 있게. (현재는 dynamic loading이 가능하게)
  • Python3 support
  • Python function tracing
  1. Script update : python을 이용해서 uftrace 데이터를 가공
  • C언어로 so파일 붙여서 사용할 수 있도록
  • lock/unlock state
  • 특정 상황을 잘 분석할 수 있는 스크립트
  1. Attache to process
  • 새로운 방식으로 통신 가능한 프로토콜 생성이 필요할 듯..
  1. Dynamic tracing
  • overhead를 줄이기 위해 원하는 몇 가지 function만 tracing 하고 싶..
    1. W/ compiler support
    1. Script to make mcount to NOP
    1. Reverse patch making NOP runtime
    1. Inject mcount call at load-time
    1. Inject mcount call at runtime (w/ attach)
  1. Signal trigger(#340)
  • process가 끝났다는 걸 따로 signal을 보낼 수 있게
  • signal로 trace를 tracing할 수 있게.
  1. Multi-data processing
  • uftrace가 1개 이상 process를 tracing할 수 있게..
  • 따로 따로 record 시킨 후 볼 때 합쳐서 실행할 수 있게
  1. Graph diff support
  • uftrace graph 를 diff할 수 있게
  • 현재는 report로만 확인 가능함
  • 터미널 환경에서 표현 상 어려움 필요 (js 필요성..)
  1. Full demangle support
  • C++ symbol을 풀어서 보여줌........
  • 현재는 외부 라이브러리 도움 받고 있음 - Without external library
  1. Flat trace
  • 현재는 function trace 를 entry / exit 에서 하고 있는데 return addr 복구 과정에서 문제가 많이 발생...
  • 원래 컴파일러가 넣어주는 함수만 tracing하는 걸로 바꾸는게 좋은듯..
  • Function entry / exit

Pro user가 되기.

순서대로 따라가면서 확인할 수 있게.

  • --nest-libcall : deps 내려가서 확인 가능하게 , 생 바이너리도 확인 가능하게

  • graph는 chrome 에서 확인할 때 help 확인 필요..

  • python server

  • -f +self : self를 더해서 볼 수 있도록

  • tui : 직접 써보기 (규모 있는 프로그램에서 사용하는 걸 추천)
    - -l : 제일 길게 걸린 함수를 보여줌 - 제일 많이 실행되는 것도 확인할 수 있음 - 아래에 라인 넘버도 확인 O -> source code도 확인 가능함. - -u : 자기의 parent로 감 - partent / child 구분 필요.

  • uftrace script

    • runtine | recording
    • python name filter : 파이썬 스크립트가 해당 name에서 실행하지 않게!!!!
    • ctx : context 정보
    • 예졔 확인
    • args : index로 indexing이 되어 있음
  • dynamic tracing

    • compiler support 필요 : NOP instruction을 삽입해야되기 때문
    • gcc mfentry 옵션
    • fxray-instrument
    • -P b option 적용 필요함! -> 그렇지 않으면 tracing 정보 확인 불가능...
  • uftrace.github.io

    • --- 는 페이지 구분
    • remark 툴 사용
    • 좋은 example 있으면 contribution해도 좋음..............

    commit 은 일단 uftrace.github.io에 하기

  • code coverage : 어디가 실행되고 실행이 안되는지 확인 가능함 + 몇 번까지 확인 가능함. -> 보다 쉽게 이해할 수 있음........!

    • 각 소스별로 확인이 가능함.
    • COVERAGE=1로 두고 빌드하면 됨!!!

4. Python trace

set-trace -> trace라는 내장 모듈이 있어서 그걸로 하면 됨.

python -m trace

line profileing -> hooking 지점이 없어서 힘들 가능성이 많음....... -> break 하나씩 걸어야 해서 오버헤드가 클 것.............................................................

5. Question

    1. -E option ? #185 test -> event 정보 (퍼프 이벤트 정보)
    1. namhyung/uftrace#457 sample하면 오래걸리지 않게.
    1. 방향성 ?
    • 속도, user 관점에서 쉽게 접근 가능
    • xray
    • 뭐든지 tool은 사람이 익숙해야된다는점.............
@claudiajkang
Copy link
Author

git log -4 --stat

@claudiajkang
Copy link
Author

python - settrace

@claudiajkang
Copy link
Author

-C option 잘 사용하면 좋음

@claudiajkang
Copy link
Author

주로 커널쪽은 커밋로그에 많음......

@claudiajkang
Copy link
Author

systab없이 kernel's header file만 있으면 됨.

@claudiajkang
Copy link
Author

build할 때
/.configure -> make -> sudo make install

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment