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