리눅스 커널 분석을 위한 vim, ctag, cscope, tagbar 세팅

지난 주말 커널 분석 수업을 들으면서 언젠간 해봐야지 마음먹었을 때 알아두면 편할것 같아서 정리.

나는 원래 vim을 주 에디터로 쓰고 firefox에도 vim key binding을 해놓는 사람이라...

리눅스 커널을 분석하려면 결국 리눅스환경에서 작업해야하는데 vim 커스터마이징을 안하는 사람들을 위한 글 + 알게된 팁들 정리용이다.

작업 환경

내가 작업을 진행한 환경은 Ubuntu 16.04, vim 8.0 을 이용했고 분석한 커널버전은 4.14.x대이다.

리눅스 커널 소스코드는 www.kernel.org에서 다운 받을 수 있다.

# jen6 at localhost.localdomain in ~/tmp [12:22:32]
→ wget 'https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.19.tar.xz'        
--2018-02-19 12:22:35--  https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.19.tar.xz
Resolving cdn.kernel.org (cdn.kernel.org)... 151.101.229.176, 2a04:4e42:36::432
접속 cdn.kernel.org (cdn.kernel.org)|151.101.229.176|:443... 접속됨.
HTTP request sent, awaiting response... 200 OK
Length: 100845536 (96M) [application/x-xz]
Saving to: ‘linux-4.14.19.tar.xz’

linux-4.14.19.tar.xz                        100%[==========================================================>]  96.17M  17.3MB/s    in 6.5s    
2018-02-19 12:22:42 (14.9 MB/s) - ‘linux-4.14.19.tar.xz’ saved [100845536/100845536]

# jen6 at localhost.localdomain in ~/tmp [12:22:42]
→ tar -xvf ./linux-4.14.19.tar.xz   

 

vim vundle설치

vim vundle은 vim의 플러그인을 설치 및 관리해주는 툴이다. 플러그인을 깔아서 커스터마이징 하다보면 어느순간 ide만큼 편해진다. 설치는 깃허브 링크로 들어가서 Quick start에 들어가 있는대로 설치를 한다.

간단하게 설명하자면

  1. ~/.vim/bundle 위 경로와 같이 홈폴더에 다음과 같은 경로로 폴더를 만들어준다.

  2. vundle을 클론 받는다

    git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
    
  3. .vimrc에 다음 내용을 추가해준다. 해당 내용은 간단하게 하기위해 주석과 필요없는걸 지웠다.

    Quick Start에 있는 vimrc에 자세한 설정방법이 있음으로 해당 링크에 있는 vimrc를 복사하길 추천한다.

    set nocompatible              " be iMproved, required
    filetype off                  " required
    
    set rtp+=~/.vim/bundle/Vundle.vim
    call vundle#begin()
    
    " let Vundle manage Vundle, required
    Plugin 'VundleVim/Vundle.vim'
    Plugin 'tpope/vim-fugitive'
    Plugin 'git://git.wincent.com/command-t.git'
    Plugin 'rstacruz/sparkup', {'rtp': 'vim/'}
    " Plugin 'ascenator/L9', {'name': 'newL9'}
    " 이부분에 플러그인 설치할 부분을 넣어주면 된다.
    
    " All of your Plugins must be added before the following line
    call vundle#end()            " required
    
    " 플러그인 설정 관련 부분은 vundle#end 밑에줄에 넣어주면 된다.
    filetype plugin indent on    " required
    
  4. vim을 켜고 :PluginInstall을 쳐서 실행시켜주면 플러그인들이 설치된다.

    이후에도 플러그인을 추가했다면 4번 과정을 해주면 된다.

     

ctags

ctags 설치

ctags는 소스코드 안에 있는 여러 함수나 변수, 구조체들을 미리 인덱싱 해놓은 후 분석할 때 해당 정의로 바로 이동할 수 있게 도와주는 툴이다. C언어 이외에도 다양한 언어를 지원함으로 vim을 주 에디터로 쓴다면 설치하면 좋은 툴이다.

  1. 먼저 ctags를 설치해준다.

    exuberant-ctagsctag종류 중 하나로써 vim에서 ctags를 쓰기위해 기존 포맷에서 확장된 형태의 툴이다.

    # jen6 at localhost.localdomain in ~/tmp [12:24:03]
    → sudo apt-get install exuberant-ctags
    
  2. ctags를 쉽게 쓸 수 있게 해주는 easytags플러그인을 설치한다

    • .vimrc에 플러그인을 추가해준다.
    Plugin 'xolox/vim-easytags'
    " 추가후 vim에서 :PluginInstall을 해준다.
    
    • 그 후 다음 설정을 vimrc에 추가해준다.
    set tag=./tags;/
    " easy-tag
    " tags를 비동기로 불러와준다. (필수) tag사이즈가 커지게 되면 vim이 블록되는 시간이 길어져서 답답하다
    let g:easytags_async=1
    " highlight를 켜면 좋지만 이것도 속도가 느려진다.
    let g:easytags_auto_highlight = 0 
    " struct의 멤버변수들도 추적이 된다.
    let g:easytags_include_members = 1
    " 현재 프로젝트에서 쓰는 tags파일을 우선 로드하고 없을 경우 global tags를 로드한다.
    let g:easytags_dynamic_files = 1
    

ctags 사용법

먼저 프로젝트나 혹은 현재 폴더에 대해서 ctags가 소스를 분석하도록 해야한다.

현재 폴더만 소스를 분석하게 하려면 ctags * 을 이용하면 되고 하위 디렉토리까지 모두 분석을 하고 싶다면 ctags -R . 을 이용하면 된다. easytags를 설치했다면 vim에서 :UpdateTags 를 하게되면 global tags를 업데이트 할 수 있다.

이후 vim에서 쓰이는 단축키 들이다.

  • Ctrl + ] - 함수, 구조체가 정의되어있는 곳으로 이동한다.
  • Ctrl + t - 이동하기 전 소스코드 위치로 돌아온다.

다른 명령어들도 있긴한데 이거 두 개만 알아도 쓸만하다. 다른 명령어가 궁금하다면 링크를 참조.

 

cscope

cscope를 쓰기 이전에는 이 함수들이 어디서 쓰이는지 혹은 전역변수들이 어디서 쓰이는지를 찾아야하는 경우 터미널 창에서 grep을 이용해야 했었다. cscope는 미리 소스코드에 대해 데이터베이스를 만들어 놓고 검색을 빠르고 편하게 할 수 있도록 도와주는 툴이다.

cscope 설치

  1. cscope를 설치해준다

    # jen6 at localhost.localdomain in ~/tmp [23:02:28]
    → sudo apt-get install cscope
    
  2. cscopevim에서 편하게 쓸 수 있도록 도와주는 quickr-cscope.vim 플러그인을 설치한다.

    Plugin 'ronakg/quickr-cscope.vim'
    
  3. vimrc에 자동으로 cscope 데이터베이스를 로드해주는 함수를 추가한다.

    function! LoadCscope()
      let db = findfile("cscope.out", ".;")
      if (!empty(db))
        let path = strpart(db, 0, match(db, "/cscope.out$"))
        set nocscopeverbose " suppress 'duplicate connection' error
        exe "cs add " . db . " " . path
        set cscopeverbose
      " else add the database pointed to by environment variable 
      elseif $CSCOPE_DB != "" 
        cs add $CSCOPE_DB
      endif
    endfunction
    au BufEnter /* call LoadCscope()
    

    코드 출처

cscope 사용법

  • C언어로 이루어진 프로젝트 폴더에서 cscope를 이용해 먼저 데이터베이스를 만들어 준다.
# jen6 at localhost.localdomain in ~/research/linux-4.14.19/kernel [23:12:18]
→ cscope -RUbq  
  • quick-cscope를 설치했다면 단축키 바인딩이 되어있다.

    • \s - 커서에 해당하는 단어에 대한 모든 심볼을 찾아준다
    • \g - 커서에 있는 단어에 대한 정의(global definition)을 찾아준다
    • \c - 커서에 있는 함수명을 호출하는 부분을 찾아준다
    • \f - 커서에 있는 파일명에 대해 모든 파일을 찾아준다
    • \i - 커서에 있는 include하는 파일을 모두 찾아준다
  • 혹시 창이 나눠져서 당황했다면 ctrl + ww로 나뉘어진 창을 넘어다니면 된다.

키바인딩이나 커스터마이징을 하고싶다면 다음 링크를 참조하자.

자세한 사용법은 man cscope 직접 찾아봅시다.

 

tagbar

현재 파일내에 있는 함수, 구조체 정의들을 옆에 빠로 한번에 볼 수 있게 해주고 점프 해준다.

tags를 이용하는 기능인데 은근 자주 쓰게되고 ide같은 화면을 만들 수 있다.

tagbar 설치

  1. majutsushi/tagbar라이브러리를 설치해준다.

    Plugin 'majutsushi/tagbar'
    

tagbar 사용법

F8버튼을 누르면 다음과 같은 화면이 나온다. ctrl + ww로 창을 넘나들면 된다.

 

 

Linux kernel에서 ctags, cscope 데이터베이스 생성하기

최근 리눅스 커널 make파일에서는 ctagscscope 데이터베이스 파일을 알아서 만들어준다.

# jen6 at localhost.localdomain in ~/research/linux-4.14.19 [23:35:53]
→ make ARCH=x86_64 cscope tags

ARCH부분은 본인이 분석하길 원하는 아키텍쳐를 넣으면 된다.

이렇게 하면 노트북 기준 10~20분 사이에 데이터베이스가 만들어진다.

(멘토님은 이 기능을 보시곤 아니 이렇게 좋은 세상이 되었다니... 하면서 감탄하셨다.)

+

언젠간... 커널도 분석해서 글을 써야지... 언젠간...


WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret
import numpy as np
import math
g = 9.81
N = 1000
tau = 20.0
dt = tau/float(N-1)

SHO

state[0] : 늘어난거리, 위치
state[1] : 속도

dv_dt 유도식

      F = -mg -kx (탄성력)
      F = ma      (뉴턴 제2법칙 가속도법칙)
      ma = -mg -kx
      a = -g -(kx/m)

x(늘어난 거리)를 이용해서 가속도를 구해주는 것

euler 함수에 들어갈 [속도, 가속도]를 구해준다

def SHO(state, time):
    dx_dt = state[1]
    dv_dt = -k/m * state[0] - g
    return np.array([dx_dt, dv_dt])

euler

1차 일반 미분 방정식의 해를 근사시켜준다…
결국 Yn+1을 Yn을 이용해서 구해준다는 이야기

[Xn + v dt, Vn + a dt] == [Xn+1, Vn+1]

def euler(y, t, dt, f):
    return y + f(y, t) * dt

k : 탄성계수

m : 질량

x0 : 초기위치

v0 : 초기속도

k = 3.5
m = 0.2
x0 = 0
v0 = 0

t = np.linspace(0.0, tau, N)
y = np.zeros((N, 2))

y[0, 0] = x0
y[0, 1] = v0
for i in range(N-1):
    y[i+1] = euler(y[i], t[i], dt, SHO)
xdata = [y[i, 0] for i in range(N)]
vdata = [y[i, 1] for i in range(N)]
from pylab import *

add plot position

subplot(2,1,1)
plot(t, xdata)
xlabel("time")
ylabel("position")
<matplotlib.text.Text at 0x22a3a2c0780>

add plot velocity

subplot(2,1,2)
plot(t, vdata)
xlabel("time")
ylabel("velocity")
show()





WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret
from random import random, seed
from math import sqrt

Monte Carlo Method

난수를 이용해 함수의 값을 확률적으로 계산하는 알고리즘
참고 url
몬테카를로 법을 이용해 pi의 근사값을 구해보자

  1. 반지름이 1인 원이 있다고 생각하자 ( $x^2 + y^2 = 1$ )
  2. 이제 그 원안에 점들을 찍는다.
    • 이때 난수가 사용된다. (점의 좌표 범위 : $ 0 \leq x \leq 1 , 0 \leq y \leq 1 $ )
    • random 함수의 값은 float으로 0~1 사이의 값이 리턴된다.
  3. 원의 넓이는 $\pi r^2$이고 정사각형의 넓이는 $4r^2$이다.
    따라서 원의 넓이를 정사각형의 넓이로 나누게 되면 $\frac{\pi}{4}$가 된다.

  4. 3번에서 구한 값에 4배를 해주면 원주율의 근사값이 나온다

#n은 점을 몇개 찍을것 인지를 지정해주는 변수 (n이 클수록 정확한 근사값을 얻을 수 있다.)
n = 10000
#inside, outside는 각각 원안에 원밖에 찍힌 점들을 저장해두는 list이다.
inside = []
outside = []
#n번 반복하면서 x, y에 random함수에서 나온 난수를 대입하고
#원안에 있는지 밖에 있는지 체크해서 넣어준다
for i in range(n):
    x = random()
    y = random()
    if sqrt(x*x + y*y) <= 1:
        inside.append([x, y])
    else:
        outside.append([x, y])
#원안에 찍힌 점들의 갯수 / 총 점의 갯수
pi = 4 * len(inside) / n
print('pi ≈ ', pi)
pi ≈  3.1436
#여기서부터는 찍힌 점을 그래프로 보여주는 코드이다. (읽을 필요 x)
import plotly.plotly as py
import plotly.graph_objs as go
inx, iny = zip(*inside)
outx, outy = zip(*outside)
inner_plot = go.Scatter (
    x = inx,
    y = iny,
    mode = 'markers',
    name = 'inCircle'
)

outter_plot = go.Scatter(
    x = outx,
    y = outy,
    mode = 'markers',
    name = 'outCircle'
)

data = [inner_plot, outter_plot]

layout = {
    'xaxis' : {
        'range' : [0, 1],
        'zeroline' : False,
        },
    'yaxis' : {
        'range' : [0, 1]
        },
    'shapes' : [
        {
            'type' : 'circle',
            'xref' : 'x',
            'yref' : 'y',
            'x0' : -1,
            'y0' : -1,
            'x1' : 1,
            'y1' : 1,
            'line' : {
                'color': 'rgba(0, 0, 0, 1)',
                'width' : 3,
            },
        },
    ]
}



fig = {
    'data' : data,
    'layout' : layout,
}
py.iplot(fig, filename='MonteCarlo_PI')

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret