tags.sh on Kernel - KAT(4-1)
Introduce
본 포스팅은 Linux kernel v5.1.0 을 기준으로 작성되었다.
linux/scripts/tags.sh에 존재
작동 조건:
make tags
make cscope
make TAGS
tags는 ctags, TAGS는 etags를 위한 tags 파일, cscope는 cscope 데이터베이스가 생성된다. 그 외로 gtags가 가능하다고 한다. 뭔지 잘 모른다.)
수행을 위해 필요한 환경변수
- ARCH: tag 등을 생성할 architechture
- arm64
- SUBARCH: 대체 언제 생성되는지 모르겠음;; 알려주길 바람.
- None
- SRCARCH: linux/arch/ 의 child directory
- arm64
- srctree: kernel root directory의 path
- make를 수행한 directory인 “.(current directory)” 다른 directory에서 수행이 안됨. -f와 -I 옵션을 줄 수는 있는데, Makefile에서 script/tag.sh을 찾지 못함.
- src: == srctree
- obj: == make 수행한 directory
make ARCH=arm64 tags cscope
Scenario
다음을 수행하였다고 가정한다.:
make ARCH=arm64 tags cscope
start
- 341:
case
문에 돌입한다.$1
은make
에서 넘겨진 인자로 보여진다. - 350: case
tags
를 수행한다. - 352:
xtags
함수를 호출하고 인자로 ctags라는 문자열을 넘긴다.341 case "$1" in 342 "cscope") 343 docscope 344 ;; 345 346 "gtags") 347 dogtags 348 ;; 349 350 "tags") 351 rm -f tags 352 xtags ctags 353 remove_structs=y 354 ;; 355 356 "TAGS") 357 rm -f TAGS 358 xtags etags 359 remove_structs=y 360 ;; 361 esac
xtags
- 288:
xtags
함수 원형 - 290: 인자
$1
(ctags
)의 버전을 출력하여 대소문자 구별 없이 exuberant라는 문자열이 존재하는지 확인. => True - 291:
exuberant
함수를 호출하고 인자로$1
(ctags
)를 전달288 xtags() 289 { 290 if $1 --version 2>&1 | grep -iq exuberant; then 291 exuberant $1 292 elif $1 --version 2>&1 | grep -iq emacs; then 293 emacs $1 294 else 295 all_target_sources | xargs $1 -a 296 fi 297 }
exuberant
- 254: ctags를 수행하는 함수
exuberant
를 수행한다. 인자로 들어온$1
은ctags
이다. - 256:
setup_regex
함수를 호출하며 인자로exuberant, asm, c
를 넘긴다. - 257:
all_target_sources
함수를 호출하며, 표준출력된 내용을ctags
($1
)의 인자로 넘긴다.(xargs
) 즉all_tager_sources
함수는 파일명이 될 것이다. 실제 태그 생성구문. - 258~270: ctags 옵션에서 잘 설명되어 있다.
- 271:
setup_regex
에서 만들어낸regex
배열을 인자로 준다. 매크로를 이용해 만든 함수 등에 대해서도 tag를 만들어주기 위함이다. - 273:
setup_regex
함수를 호출하며 인자로exuberant, kconfig
를 넘긴다. - 274:
all_kconfigs
함수를 호출하며, 표준출력된 내용을ctags
($1
)의 인자로 넘긴다. - 275: ctags 옵션에서 정확하게 설명되어 있다.
kconfig라는 언어는 없기 때문에
regex
배열에 kconfig tag를 생성하는 정규표현식을setup_regex
에서 만든다.254 exuberant() 255 { 256 setup_regex exuberant asm c 257 all_target_sources | xargs $1 -a \ 258 -I __initdata,__exitdata,__initconst,__ro_after_init \ 259 -I __initdata_memblock \ 260 -I __refdata,__attribute,__maybe_unused,__always_unused \ 261 -I __acquires,__releases,__deprecated,__always_inline \ 262 -I __read_mostly,__aligned,____cacheline_aligned \ 263 -I ____cacheline_aligned_in_smp \ 264 -I __cacheline_aligned,__cacheline_aligned_in_smp \ 265 -I ____cacheline_internodealigned_in_smp \ 266 -I __used,__packed,__packed2__,__must_check,__must_hold \ 267 -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \ 268 -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ 269 -I static,const \ 270 --extra=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \ 271 "${regex[@]}" 272 273 setup_regex exuberant kconfig 274 all_kconfigs | xargs $1 -a \ 275 --langdef=kconfig --language-force=kconfig "${regex[@]}" 276 277 }
setup_regex
setup_regex
함수의 원형이다.- 223: local 변수로
mode=$1(exuberant), lang, tmp=(), r
총 4개를 선언한다. - 224:
setup_regex
로 들어온 첫 번째 인자(exuberant)를 제거한다. (남은 두 인자는 asm과 c) - 226:
regex
라는 전역 배열을 선언한다. (regex는 regular expression의 준말로 보인다.) - 227:
shift
하여 제거한 첫 번째 인자를 제외한 두 번째 인자부터 마지막 인자까지 for 문을 수행.for lang in $@; do
와 완전히 동일한 문장이다. - 228~232:
$lang
이 asm 이면tmp
에$regex_asm
의 인자 전부를tmp
에 대입, c면$regex_c
, kconfig면$regex_kconfig
를 대입한다. tmp
에 들어간 elements들을 순회하는 for문- 234:
$mode(exuberant) == "exuberant"
이므로 참. - 235:
regex
배열에--regex-$lang=${r}b
를 추가함.--regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
:regexp
에 해당하는 문자열을replacement
로 바꿔 tag로 만듬.replacement
가 tag 이름regexp
가 표현식,[kind-spec]
이 tagfield의 kind에 대한 value(없으면 regex 라는 의미의 r).[flags]
는 b 라는 단일 문자에 해당하는 필드로 base regular expression을 의미함.
- 236~: exuberant ctags를 사용하지 않을 때(etags 등) 사용하는 부분. (분석생략.)
221 setup_regex() 222 { 223 local mode=$1 lang tmp=() r 224 shift 225 226 regex=() 227 for lang; do 228 case "$lang" in 229 asm) tmp=("${regex_asm[@]}") ;; 230 c) tmp=("${regex_c[@]}") ;; 231 kconfig) tmp=("${regex_kconfig[@]}") ;; 232 esac 233 for r in "${tmp[@]}"; do 234 if test "$mode" = "exuberant"; then 235 regex[${#regex[@]}]="--regex-$lang=${r}b" 236 else 237 # Remove ctags /kind-spec/ 238 case "$r" in 239 /*/*/?/) 240 r=${r%?/} 241 esac 242 # Prepend ^[^#] unless already anchored 243 case "$r" in 244 /^*) ;; 245 *) 246 r="/^[^#]*${r#/}" 247 esac 248 regex[${#regex[@]}]="--regex=$r" 249 fi 250 done 251 done 252 }
regex_lang
ctags를 위한 /kind-spec/ 옵션이 있는 베이직 정규 표현식과 따라야 하는 제한.
- 정규표현식 수정자 없음
- \? 대신 {0,1}을 사용해야함. 왜냐하면 etags에서는 ? 문자 자체를 의미하게 될 수 있음.
- etags에서는 \s가 동작하지 앟음. 스페이스나 [ \t]를 사용해야함.
- \w는 동작하지만 etags에서 underscores(_)와 일치하지 않음
- 마지막줄은 해석이 안 되는데 도와주세요.
asm
ENTRY나 _GLOBAL이 붙은 어셈블리 프로시저. 외부 모듈에게 노출하기 위해 사용하는 매크로이다.
c
SYSCALL_DEFINE이나 TRACE_EVENT, DEFINE 등과 같은 매크로를 이용한 함수 선언문에 대해서 tag를 생성해주기 위함이다.
kconfig
kconfig의 tag는 Kconfig 파일에 존재하는 config에 대해서 모든 태그를 생성한다. kconfig에서는 ‘CONFIG_‘가 붙지 않고, 실제 코드에서 #ifdef 등에서 사용될 땐, ‘CONFIG_‘가 붙으므로 붙은 것과 안 붙은 것으로 태그를 두 개 생성한다.
142 # Basic regular expressions with an optional /kind-spec/ for ctags and
143 # the following limitations:
144 # - No regex modifiers
145 # - Use \{0,1\} instead of \?, because etags expects an unescaped ?
146 # - \s is not working with etags, use a space or [ \t]
147 # - \w works, but does not match underscores in etags
148 # - etags regular expressions have to match at the start of a line;
149 # a ^[^#] is prepended by setup_regex unless an anchor is already present
150 regex_asm=(
151 '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/'
152 )
153 regex_c=(
154 '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/'
155 '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/'
156 '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/'
157 '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/'
158 '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
159 '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/'
160 '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
161 '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/'
162 '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/'
163 '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
164 '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
165 '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
166 '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
167 '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
168 '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
169 '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
170 '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
171 '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
172 '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
173 '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
174 '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
175 '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
176 '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/'
177 '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
178 '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
179 '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/'
180 '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/'
181 '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/'
182 '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/'
183 '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/'
184 '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/'
185 '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/'
186 '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/'
187 '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/'
188 '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/'
189 '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/'
190 '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/'
191 '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/'
192 '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/'
193 '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/'
194 '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/'
195 '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/'
196 '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/'
197 '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/'
198 '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/'
199 '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/'
200 '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/'
201 '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/'
202 '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/'
203 '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/'
204 '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/'
205 '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/'
206 '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/'
207 '/\<DEFINE_ID\(R\|A\)(\([[:alnum:]_]\+\)/\2/'
208 '/\<DEFINE_WD_CLASS(\([[:alnum:]_]\+\)/\1/'
209 '/\<ATOMIC_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
210 '/\<RAW_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
211 '/\<DECLARE_FAULT_ATTR(\([[:alnum:]_]\+\)/\1/'
212 '/\<BLOCKING_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
213 '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/'
214 '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/'
215 '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/'
216 )
217 regex_kconfig=(
218 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'
219 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/CONFIG_\2/'
220 )
all_target_sources
ctags를 만들어낼 타겟 c/h/S 파일들을 출력
$COMPILED_SOURCE == None
- 112:
all_target_sources
함수의 원형이다. - 114: 컴파일된 소스가 없으므로 (컴파일 하면 참이되는지는 해보지 않았다.) 거짓.
- 117:
all_sources
함수를 수행한다.112 all_target_sources() 113 { 114 if [ -n "$COMPILED_SOURCE" ]; then 115 all_compiled_sources 116 else 117 all_sources 118 fi 119 }
all_sources
- tag를 만들 모든 소스 파일을 찾음.
${SRCARCH} == "arm64"
-
$ALLSOURCE_ARCHS == "arm64"
- 82: arch/arm64/include 내부의 c/h/S 파일들 출력
- 83: 거짓
- 86: include 내부의 c/h/S 파일들 출력
- 89:
find_sources arm64 '*.[chS]'
- arch/arm64 의 include를 제외한 c/h/S 파일들 출력
- 91: arch와 include 디렉토리를 제외한 c/h/S 파일들 출력
80 all_sources() 81 { 82 find_arch_include_sources ${SRCARCH} '*.[chS]' 83 if [ ! -z "$archinclude" ]; then 84 find_arch_include_sources $archinclude '*.[chS]' 85 fi 86 find_include_sources '*.[chS]' 87 for arch in $ALLSOURCE_ARCHS 88 do 89 find_sources $arch '*.[chS]' 90 done 91 find_other_sources '*.[chS]' 92 }
find_arch_include_sources
$subarchprune == None
-
$ignore == "( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git ) -prune -o ( -name *.mod.c ) -prune -o ( -path tools ) -prune -o"
- 51: arch/arm64/include 를
include
에 저장 - 54: 그대로
$include
- 55: arch/arm64/include 디렉토리 내부에
$ignore
에 해당하는 파일들을 제외하고 symbolic link 파일이 아닌 인자로 들어온 확장자 파일을 전부 출력.48 # find sources in arch/$1/include 49 find_arch_include_sources() 50 { 51 include=$(find ${tree}arch/$1/ $subarchprune \ 52 -name include -type d -print); 53 if [ -n "$include" ]; then 54 archincludedir="$archincludedir $include" 55 find $include $ignore -name "$2" -not -type l -print; 56 fi 57 }
find_include_sources
- 62: include 디렉토리 내부에
$ignore
을 제외하고 심볼릭 링크 파일이 아닌 인자로 들어온 확장자 파일을 전부 출력59 # find sources in include/ 60 find_include_sources() 61 { 62 find ${tree}include $ignore -name config -prune -o -name "$1" \ 63 -not -type l -print; 64 }
find_sources
75 find_sources()
76 {
77 find_arch_sources $1 "$2"
78 }
find_arch_sources
-
$archincludedir == "arch/arm64/include"
- 42:
$prune == "-wholename arch/arm64/include -prune -o"
- 44: arch/arm64 에 include 디렉토리만 빼고 심볼릭 링크가 아닌 인자로 들어온 파일을 출력
38 # find sources in arch/$ARCH 39 find_arch_sources() 40 { 41 for i in $archincludedir; do 42 prune="$prune -wholename $i -prune -o" 43 done 44 find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" \ 45 -not -type l -print; 46 }
find_other_sources
- 70: include와 arch 디렉터리, .tmp_로 시작하는 파일들을 제외하고 심볼릭 링크가 아닌
인자로 들어온 파일을 출력
66 # find sources in rest of tree 67 # we could benefit from a list of dirs to search in here 68 find_other_sources() 69 { 70 find ${tree}* $ignore \ 71 \( -path ${tree}include -o -path ${tree}arch -o -name '.tmp_*' \) -prune -o \ 72 -name "$1" -not -type l -print;
all_kconfigs
타겟 arch와 나머지 디렉토리의 Kconfig 파일을 출력
121 all_kconfigs()
122 {
123 find ${tree}arch/ -maxdepth 1 $ignore \
124 -name "Kconfig*" -not -type l -print;
125 for arch in $ALLSOURCE_ARCHS; do
126 find_sources $arch 'Kconfig*'
127 done
128 find_other_sources 'Kconfig*'
129 }
댓글남기기