linux/scripts/tags.sh
<<
>>
Prefs
   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# ignore userspace tools
  29if [ -n "$COMPILED_SOURCE" ]; then
  30        ignore="$ignore ( -path ./tools ) -prune -o"
  31else
  32        ignore="$ignore ( -path ${tree}tools ) -prune -o"
  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        realpath -es $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) \
  99                include/generated/autoconf.h $(find $ignore -name "*.cmd" -exec \
 100                grep -Poh '(?(?=^source_.* \K).*|(?=^  \K\S).*(?= \\))' {} \+ |
 101                awk '!a[$0]++') | sort -u
 102}
 103
 104all_target_sources()
 105{
 106        if [ -n "$COMPILED_SOURCE" ]; then
 107                all_compiled_sources
 108        else
 109                all_sources
 110        fi
 111}
 112
 113all_kconfigs()
 114{
 115        find ${tree}arch/ -maxdepth 1 $ignore \
 116               -name "Kconfig*" -not -type l -print;
 117        for arch in $ALLSOURCE_ARCHS; do
 118                find_sources $arch 'Kconfig*'
 119        done
 120        find_other_sources 'Kconfig*'
 121}
 122
 123docscope()
 124{
 125        (echo \-k; echo \-q; all_target_sources) > cscope.files
 126        cscope -b -f cscope.out
 127}
 128
 129dogtags()
 130{
 131        all_target_sources | gtags -i -f -
 132}
 133
 134# Basic regular expressions with an optional /kind-spec/ for ctags and
 135# the following limitations:
 136# - No regex modifiers
 137# - Use \{0,1\} instead of \?, because etags expects an unescaped ?
 138# - \s is not working with etags, use a space or [ \t]
 139# - \w works, but does not match underscores in etags
 140# - etags regular expressions have to match at the start of a line;
 141#   a ^[^#] is prepended by setup_regex unless an anchor is already present
 142regex_asm=(
 143        '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/'
 144)
 145regex_c=(
 146        '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/'
 147        '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/'
 148        '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/'
 149        '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/'
 150        '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
 151        '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/'
 152        '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
 153        '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/'
 154        '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/'
 155        '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
 156        '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
 157        '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
 158        '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
 159        '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
 160        '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
 161        '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
 162        '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
 163        '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
 164        '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
 165        '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
 166        '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
 167        '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
 168        '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/'
 169        '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
 170        '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
 171        '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/'
 172        '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/'
 173        '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/'
 174        '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/'
 175        '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/'
 176        '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/'
 177        '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/'
 178        '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/'
 179        '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/'
 180        '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/'
 181        '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/'
 182        '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/'
 183        '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/'
 184        '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/'
 185        '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/'
 186        '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/'
 187        '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/'
 188        '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/'
 189        '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/'
 190        '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/'
 191        '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/'
 192        '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/'
 193        '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/'
 194        '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/'
 195        '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/'
 196        '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/'
 197        '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/'
 198        '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/'
 199        '/\<DEFINE_ID\(R\|A\)(\([[:alnum:]_]\+\)/\2/'
 200        '/\<DEFINE_WD_CLASS(\([[:alnum:]_]\+\)/\1/'
 201        '/\<ATOMIC_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
 202        '/\<RAW_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
 203        '/\<DECLARE_FAULT_ATTR(\([[:alnum:]_]\+\)/\1/'
 204        '/\<BLOCKING_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
 205        '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/'
 206        '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/'
 207        '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/'
 208        '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/'
 209        '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
 210)
 211regex_kconfig=(
 212        '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'
 213        '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/CONFIG_\2/'
 214)
 215setup_regex()
 216{
 217        local mode=$1 lang tmp=() r
 218        shift
 219
 220        regex=()
 221        for lang; do
 222                case "$lang" in
 223                asm)       tmp=("${regex_asm[@]}") ;;
 224                c)         tmp=("${regex_c[@]}") ;;
 225                kconfig)   tmp=("${regex_kconfig[@]}") ;;
 226                esac
 227                for r in "${tmp[@]}"; do
 228                        if test "$mode" = "exuberant"; then
 229                                regex[${#regex[@]}]="--regex-$lang=${r}b"
 230                        else
 231                                # Remove ctags /kind-spec/
 232                                case "$r" in
 233                                /*/*/?/)
 234                                        r=${r%?/}
 235                                esac
 236                                # Prepend ^[^#] unless already anchored
 237                                case "$r" in
 238                                /^*) ;;
 239                                *)
 240                                        r="/^[^#]*${r#/}"
 241                                esac
 242                                regex[${#regex[@]}]="--regex=$r"
 243                        fi
 244                done
 245        done
 246}
 247
 248exuberant()
 249{
 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        --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