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