1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0-only 3# Generate tags or cscope files 4# Usage tags.sh <mode> 5# 6# mode may be any of: tags, TAGS, cscope 7# 8# Uses the following environment variables: 9# SUBARCH, SRCARCH, srctree 10 11if [ "$KBUILD_VERBOSE" = "1" ]; then 12 set -x 13fi 14 15# RCS_FIND_IGNORE has escaped ()s -- remove them. 16ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )" 17# tags and cscope files should also ignore MODVERSION *.mod.c files 18ignore="$ignore ( -name *.mod.c ) -prune -o" 19 20# Use make KBUILD_ABS_SRCTREE=1 {tags|cscope} 21# to force full paths for a non-O= build 22if [ "${srctree}" = "." -o -z "${srctree}" ]; then 23 tree= 24else 25 tree=${srctree}/ 26fi 27 28# Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH 29if [ "${ALLSOURCE_ARCHS}" = "" ]; then 30 ALLSOURCE_ARCHS=${SRCARCH} 31elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then 32 ALLSOURCE_ARCHS=$(find ${tree}arch/ -mindepth 1 -maxdepth 1 -type d -printf '%f ') 33fi 34 35# find sources in arch/$1 36find_arch_sources() 37{ 38 for i in $archincludedir; do 39 prune="$prune -wholename $i -prune -o" 40 done 41 find ${tree}arch/$1 $ignore $prune -name "$2" -not -type l -print; 42} 43 44# find sources in arch/$1/include 45find_arch_include_sources() 46{ 47 include=$(find ${tree}arch/$1/ -name include -type d -print); 48 if [ -n "$include" ]; then 49 archincludedir="$archincludedir $include" 50 find $include $ignore -name "$2" -not -type l -print; 51 fi 52} 53 54# find sources in include/ 55find_include_sources() 56{ 57 find ${tree}include $ignore -name config -prune -o -name "$1" \ 58 -not -type l -print; 59} 60 61# find sources in rest of tree 62# we could benefit from a list of dirs to search in here 63find_other_sources() 64{ 65 find ${tree}* $ignore \ 66 \( -path ${tree}include -o -path ${tree}arch -o -name '.tmp_*' \) -prune -o \ 67 -name "$1" -not -type l -print; 68} 69 70find_sources() 71{ 72 find_arch_sources $1 "$2" 73} 74 75all_sources() 76{ 77 find_arch_include_sources ${SRCARCH} '*.[chS]' 78 if [ ! -z "$archinclude" ]; then 79 find_arch_include_sources $archinclude '*.[chS]' 80 fi 81 find_include_sources '*.[chS]' 82 for arch in $ALLSOURCE_ARCHS 83 do 84 find_sources $arch '*.[chS]' 85 done 86 find_other_sources '*.[chS]' 87} 88 89all_compiled_sources() 90{ 91 { 92 echo include/generated/autoconf.h 93 find $ignore -name "*.cmd" -exec \ 94 grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ | 95 awk '!a[$0]++' 96 } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) | 97 sort -u 98} 99 100all_target_sources() 101{ 102 if [ -n "$COMPILED_SOURCE" ]; then 103 all_compiled_sources 104 else 105 all_sources 106 fi 107} 108 109all_kconfigs() 110{ 111 find ${tree}arch/ -maxdepth 1 $ignore \ 112 -name "Kconfig*" -not -type l -print; 113 for arch in $ALLSOURCE_ARCHS; do 114 find_sources $arch 'Kconfig*' 115 done 116 find_other_sources 'Kconfig*' 117} 118 119docscope() 120{ 121 (echo \-k; echo \-q; all_target_sources) > cscope.files 122 cscope -b -f cscope.out 123} 124 125dogtags() 126{ 127 all_target_sources | gtags -i -f - 128} 129 130# Basic regular expressions with an optional /kind-spec/ for ctags and 131# the following limitations: 132# - No regex modifiers 133# - Use \{0,1\} instead of \?, because etags expects an unescaped ? 134# - \s is not working with etags, use a space or [ \t] 135# - \w works, but does not match underscores in etags 136# - etags regular expressions have to match at the start of a line; 137# a ^[^#] is prepended by setup_regex unless an anchor is already present 138regex_asm=( 139 '/^\(ENTRY\|_GLOBAL\)([[:space:]]*\([[:alnum:]_\\]*\)).*/\2/' 140) 141regex_c=( 142 '/^SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/sys_\1/' 143 '/^BPF_CALL_[0-9]([[:space:]]*\([[:alnum:]_]*\).*/\1/' 144 '/^COMPAT_SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/compat_sys_\1/' 145 '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' 146 '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' 147 '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' 148 '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' 149 '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/get_\1_slot/' 150 '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/free_\1_slot/' 151 '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' 152 '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' 153 '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' 154 '/^TESTSETFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/' 155 '/^TESTPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' 156 '/^SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' 157 '/\<__SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' 158 '/\<TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' 159 '/\<__TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' 160 '/\<CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' 161 '/\<__CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' 162 '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' 163 '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' 164 '/^PAGEFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' 165 '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/' 166 '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' 167 '/\<SETPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' 168 '/\<CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' 169 '/\<__CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' 170 '/\<TESTCLEARFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' 171 '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' 172 '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' 173 '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' 174 '/^TASK_PFA_TEST([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_\1/' 175 '/^TASK_PFA_SET([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_set_\1/' 176 '/^TASK_PFA_CLEAR([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_clear_\1/' 177 '/^DEF_MMIO_\(IN\|OUT\)_[XD]([[:space:]]*\([[:alnum:]_]*\),[^)]*)/\2/' 178 '/^DEBUGGER_BOILERPLATE([[:space:]]*\([[:alnum:]_]*\))/\1/' 179 '/^DEF_PCI_AC_\(\|NO\)RET([[:space:]]*\([[:alnum:]_]*\).*/\2/' 180 '/^PCI_OP_READ([[:space:]]*\(\w*\).*[1-4])/pci_bus_read_config_\1/' 181 '/^PCI_OP_WRITE([[:space:]]*\(\w*\).*[1-4])/pci_bus_write_config_\1/' 182 '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 183 '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 184 '/\<DECLARE_\(RWSEM\|COMPLETION\)([[:space:]]*\([[:alnum:]_]\+\)/\2/v/' 185 '/\<DECLARE_BITMAP([[:space:]]*\([[:alnum:]_]*\)/\1/v/' 186 '/\(^\|\s\)\(\|L\|H\)LIST_HEAD([[:space:]]*\([[:alnum:]_]*\)/\3/v/' 187 '/\(^\|\s\)RADIX_TREE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 188 '/\<DEFINE_PER_CPU([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/' 189 '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/' 190 '/\<DECLARE_WAIT_QUEUE_HEAD([[:space:]]*\([[:alnum:]_]*\)/\1/v/' 191 '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 192 '/\(^\s\)OFFSET([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 193 '/\(^\s\)DEFINE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 194 '/\<\(DEFINE\|DECLARE\)_HASHTABLE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' 195 '/\<DEFINE_ID\(R\|A\)([[:space:]]*\([[:alnum:]_]\+\)/\2/' 196 '/\<DEFINE_WD_CLASS([[:space:]]*\([[:alnum:]_]\+\)/\1/' 197 '/\<ATOMIC_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' 198 '/\<RAW_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' 199 '/\<DECLARE_FAULT_ATTR([[:space:]]*\([[:alnum:]_]\+\)/\1/' 200 '/\<BLOCKING_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' 201 '/\<DEVICE_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/dev_attr_\2/' 202 '/\<DRIVER_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/driver_attr_\2/' 203 '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)([[:space:]]*\([[:alnum:]_]\+\)/\4/' 204 '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/' 205 '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/' 206) 207regex_kconfig=( 208 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' 209 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/CONFIG_\2/' 210) 211setup_regex() 212{ 213 local mode=$1 lang tmp=() r 214 shift 215 216 regex=() 217 for lang; do 218 case "$lang" in 219 asm) tmp=("${regex_asm[@]}") ;; 220 c) tmp=("${regex_c[@]}") ;; 221 kconfig) tmp=("${regex_kconfig[@]}") ;; 222 esac 223 for r in "${tmp[@]}"; do 224 if test "$mode" = "exuberant"; then 225 regex[${#regex[@]}]="--regex-$lang=${r}b" 226 else 227 # Remove ctags /kind-spec/ 228 case "$r" in 229 /*/*/?/) 230 r=${r%?/} 231 esac 232 # Prepend ^[^#] unless already anchored 233 case "$r" in 234 /^*) ;; 235 *) 236 r="/^[^#]*${r#/}" 237 esac 238 regex[${#regex[@]}]="--regex=$r" 239 fi 240 done 241 done 242} 243 244exuberant() 245{ 246 CTAGS_EXTRA="extra" 247 if $1 --version 2>&1 | grep -iq universal; then 248 CTAGS_EXTRA="extras" 249 fi 250 setup_regex exuberant asm c 251 all_target_sources | xargs $1 -a \ 252 -I __initdata,__exitdata,__initconst,__ro_after_init \ 253 -I __initdata_memblock \ 254 -I __refdata,__attribute,__maybe_unused,__always_unused \ 255 -I __acquires,__releases,__deprecated,__always_inline \ 256 -I __read_mostly,__aligned,____cacheline_aligned \ 257 -I ____cacheline_aligned_in_smp \ 258 -I __cacheline_aligned,__cacheline_aligned_in_smp \ 259 -I ____cacheline_internodealigned_in_smp \ 260 -I __used,__packed,__packed2__,__must_check,__must_hold \ 261 -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \ 262 -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ 263 -I static,const \ 264 --$CTAGS_EXTRA=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \ 265 "${regex[@]}" 266 267 setup_regex exuberant kconfig 268 all_kconfigs | xargs $1 -a \ 269 --langdef=kconfig --language-force=kconfig "${regex[@]}" 270 271} 272 273emacs() 274{ 275 setup_regex emacs asm c 276 all_target_sources | xargs $1 -a "${regex[@]}" 277 278 setup_regex emacs kconfig 279 all_kconfigs | xargs $1 -a "${regex[@]}" 280} 281 282xtags() 283{ 284 if $1 --version 2>&1 | grep -iq exuberant; then 285 exuberant $1 286 elif $1 --version 2>&1 | grep -iq emacs; then 287 emacs $1 288 else 289 all_target_sources | xargs $1 -a 290 fi 291} 292 293# Support um (which uses SUBARCH) 294if [ "${ARCH}" = "um" ]; then 295 if [ "$SUBARCH" = "i386" ]; then 296 archinclude=x86 297 elif [ "$SUBARCH" = "x86_64" ]; then 298 archinclude=x86 299 else 300 archinclude=${SUBARCH} 301 fi 302fi 303 304remove_structs= 305case "$1" in 306 "cscope") 307 docscope 308 ;; 309 310 "gtags") 311 dogtags 312 ;; 313 314 "tags") 315 rm -f tags 316 xtags ctags 317 remove_structs=y 318 ;; 319 320 "TAGS") 321 rm -f TAGS 322 xtags etags 323 remove_structs=y 324 ;; 325esac 326 327# Remove structure forward declarations. 328if [ -n "$remove_structs" ]; then 329 LC_ALL=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' $1 330fi 331