-
Notifications
You must be signed in to change notification settings - Fork 1
/
linux.sh
executable file
·342 lines (313 loc) · 16.6 KB
/
linux.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#!/bin/bash
add-linux-system() {
if [[ $LINUX_CLONE_MODE == filter ]]; then
add-hook-step post-clone-hook linux "$(to-lambda post-clone-hook-linux)"
fi
add-hook-step kconfig-post-checkout-hook linux "$(to-lambda kconfig-post-checkout-hook-linux)"
add-hook-step kconfig-pre-binding-hook linux "$(to-lambda kconfig-pre-binding-hook-linux)"
if [[ $LINUX_CLONE_MODE == fork ]]; then
local url=https://github.com/ekuiter/linux
elif [[ $LINUX_CLONE_MODE == original ]] || [[ $LINUX_CLONE_MODE == filter ]]; then
local url=https://github.com/torvalds/linux
else
error "Unknown Linux clone mode: $LINUX_CLONE_MODE"
fi
add-system --system linux --url "$url"
}
post-clone-hook-linux(system, revision) {
if [[ $system == linux ]]; then
# we need to purge a few files from the git history, which cannot be checked out on case-insensitive file systems. this changes all commit hashes.
# if you need the original commit hashes, please use LINUX_CLONE_MODE=original
git -C "$(input-directory)/linux" filter-repo --force --invert-paths --path include/uapi/linux/netfilter/xt_CONNMARK.h --path include/uapi/linux/netfilter/xt_connmark.h --path include/uapi/linux/netfilter/xt_DSCP.h --path include/uapi/linux/netfilter/xt_dscp.h --path include/uapi/linux/netfilter/xt_MARK.h --path include/uapi/linux/netfilter/xt_mark.h --path include/uapi/linux/netfilter/xt_RATEEST.h --path include/uapi/linux/netfilter/xt_rateest.h --path include/uapi/linux/netfilter/xt_TCPMSS.h --path include/uapi/linux/netfilter/xt_tcpmss.h --path include/uapi/linux/netfilter_ipv4/ipt_ECN.h --path include/uapi/linux/netfilter_ipv4/ipt_ecn.h --path include/uapi/linux/netfilter_ipv4/ipt_TTL.h --path include/uapi/linux/netfilter_ipv4/ipt_ttl.h --path include/uapi/linux/netfilter_ipv6/ip6t_HL.h --path include/uapi/linux/netfilter_ipv6/ip6t_hl.h --path net/netfilter/xt_DSCP.c --path net/netfilter/xt_dscp.c --path net/netfilter/xt_HL.c --path net/netfilter/xt_hl.c --path net/netfilter/xt_RATEEST.c --path net/netfilter/xt_rateest.c --path net/netfilter/xt_TCPMSS.c --path net/netfilter/xt_tcpmss.c --path tools/memory-model/litmus-tests/Z6.0+pooncelock+poonceLock+pombonce.litmus --path tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus
fi
}
kconfig-post-checkout-hook-linux(system, revision) {
if [[ $system == linux ]]; then
replace-linux(regex, replacement=) { find ./ -type f -name "*Kconfig*" -exec sed -i "s/$regex/$replacement/g" {} \;; }
# ignore all constraints that use the newer $(success,...) syntax
replace-linux "\s*default \$(.*" # default values are not translated into the formula anyway, so we can ignore them
replace-linux "\s*depends on \$(.*" # for simplicity, we ignore machine-dependent dependencies, which describe inter-machine variability
replace-linux "def_bool \$(.*" 'bool "machine-dependent feature"' # as above, ignore default value and translate as normal Boolean feature
# ugly hack for linux 6.0 due to multiline def_bool (https://github.com/torvalds/linux/blob/v6.0/arch/x86/Kconfig#L1834)
replace-linux "def_bool ((.*" 'bool "machine-dependent feature"'
replace-linux "\s*(CC_IS_CLANG && CLANG_VERSION >= 140000).*"
replace-linux "\s*\$(as-instr,endbr64).*"
fi
}
kconfig-pre-binding-hook-linux(system, revision, kconfig_binding_directory=) {
if [[ $system == linux ]]; then
echo -n '-DSYSTEM_IS_LINUX'
# sym_is_optional was removed in Linux 6.10
if grep -qrnw "$kconfig_binding_directory" -e sym_is_optional 2>/dev/null; then
echo -n ' -DSYM_IS_OPTIONAL'
fi
# sym_get_choice_prop was removed in Linux 6.11
if grep -qrnw "$kconfig_binding_directory" -e sym_get_choice_prop 2>/dev/null; then
echo -n ' -DSYM_GET_CHOICE_PROP'
fi
# in Linux 6.11, some helpers have been moved (https://github.com/torvalds/linux/commit/fbaf242c956aff6a07d9e97eaa3a0a48d947de33)
echo -n ' -Iscripts/include'
fi
}
linux-tag-revisions() {
git-tag-revisions linux | exclude-revision tree rc "v.*\..*\..*\..*"
}
linux-architectures(revision) {
git -C "$(input-directory)/linux" ls-tree -rd "$revision" --name-only \
| grep ^arch/ | cut -d/ -f2 | sort | uniq | grep -v '^um$'
}
linux-configs(revision) {
# match lines in all Kconfig files of the given revision that:
# - start with 'config' or 'menuconfig' (possibly with leading whitespace)
# - after which follows an alphanumeric configuration option name
# then format the result by removing 'config' or 'menuconfig', possible comments, and trimming any whitespace
# finally, ignore all lines which contain illegal characters (e.g., whitespace)
# note that this does not exclude the architecture um as done in other functions
git -C "$(input-directory)/linux" grep -E $'^[ \t]*(menu)?config[ \t]+[0-9a-zA-Z_]+' "$revision" -- '**/*Kconfig*' \
| awk -F: $'{OFS=","; gsub("^[ \t]*(menu)?config[ \t]+", "", $3); gsub("#.*", "", $3); gsub(/^[[:space:]]+|[[:space:]]+$/, "", $3); print "linux", $1, $2, $3}' \
| grep -E ',.*,.*,[0-9a-zA-Z_]+$' \
| sort | uniq
}
linux-config-types(revision) {
# similar to linux-configs, reads all configuration options, but also tries to read their types from the succeeding line
# note that this is less accurate than linux-configs due to the complexity of the regular expressions
# also, this does not exclude the architecture um as done in other functions
git -C "$(input-directory)/linux" grep -E -A1 $'^[ \t]*(menu)?config[ \t]+[0-9a-zA-Z_]+' "$revision" -- '**/*Kconfig*' \
| perl -pe 's/[ \t]*(menu)?config[ \t]+([0-9a-zA-Z_]+).*/$2/' \
| perl -pe 's/\n/&&&/g' \
| perl -pe 's/&&&--&&&/\n/g' \
| perl -pe 's/&&&[^:&]*?:[^:&]*?Kconfig[^:&]*?-/&&&/g' \
| perl -pe 's/&&&([^:&]*?:[^:&]*?Kconfig[^:&]*?:)/&&&\n$1/g' \
| perl -pe 's/&&&/:/g' \
| awk -F: $'{OFS=","; gsub(".*bool.*", "bool", $4); gsub(".*tristate.*", "tristate", $4); gsub(".*string.*", "string", $4); gsub(".*int.*", "int", $4); gsub(".*hex.*", "hex", $4); print "linux", $1, $2, $3, $4}' \
| grep -E ',(bool|tristate|string|int|hex)$' \
| sort | uniq
}
linux-attempt-grouper(file) {
# shellcheck disable=SC2001
echo "$file" | sed 's#\(.*\)/linux/.*\[\(.*\)\]\..*#\1.\2#'
}
add-linux-kconfig(revision, architecture=x86, kconfig_binding_file=) {
if [[ $architecture == x86 ]] && linux-architectures "$revision" | grep -q '^i386$'; then
architecture=i386 # in old revisions, x86 is called i386
fi
if [[ $architecture == um ]]; then
error "User mode Linux is currently not supported."
fi
if [[ $architecture == all ]]; then
mapfile -t architectures < <(linux-architectures "$revision")
for architecture in "${architectures[@]}"; do
add-linux-kconfig "$revision" "$architecture" "$kconfig_binding_file"
done
return
fi
# ARCH speficies the architecture of the targeted system, SRCARCH the architecture of the compiling system
# SUBARCH is only taken into account for user mode Linux (um), where it specifies the underlying targeted system architecture
# here we assume native compilation (no cross-compilation) without user mode Linux
# srctree is needed by later revisions to access scripts (e.g., in scripts/Kconfig.include)
# CC and LD are also used in scripts/Kconfig.include
# KERNELVERSION is generally unused and only defined to avoid warnings
local environment=SUBARCH=$architecture,ARCH=$architecture,SRCARCH=$architecture,srctree=.,CC=cc,LD=ld,KERNELVERSION=$revision
# locate the main Kconfig file, which is arch/.../Kconfig in old revisions and Kconfig in new revisions
local kconfig_file
kconfig_file=$({ git -C "$(input-directory)/linux" show "$revision:scripts/kconfig/Makefile" | grep "^Kconfig := [^$]" | cut -d' ' -f3; } || true)
kconfig_file=${kconfig_file:-arch/\$(SRCARCH)/Kconfig}
kconfig_file=${kconfig_file//\$(SRCARCH)/$architecture}
add-linux-system
add-revision --system linux --revision "$revision"
if [[ -n $kconfig_binding_file ]]; then
add-kconfig-model \
--system linux \
--revision "${revision}[$architecture]" \
--kconfig-file "$kconfig_file" \
--kconfig-binding-file "$kconfig_binding_file" \
--environment "$environment"
else
add-kconfig \
--system linux \
--revision "${revision}[$architecture]" \
--kconfig-file "$kconfig_file" \
--kconfig-binding-files scripts/kconfig/*.o \
--environment "$environment"
fi
}
add-linux-kconfig-binding(revision) {
add-linux-system
add-kconfig-binding --system linux --revision "$revision" --kconfig_binding_files scripts/kconfig/*.o
}
linux-kconfig-binding-file(revision) {
output-path "$KCONFIG_BINDINGS_OUTPUT_DIRECTORY" linux "$revision"
}
add-linux-kconfig-revisions(revisions=, architecture=x86) {
if [[ -z $revisions ]]; then
return
fi
# for up to linux 2.6.9, use the kconfig parser of linux 2.6.9 for extraction, as previous versions cannot be compiled
local first_binding_revision=v2.6.9
local first_binding_timestamp current_timestamp
first_binding_timestamp=$(git-timestamp linux "$first_binding_revision")
while read -r revision; do
current_timestamp=$(git-timestamp linux "$revision")
if [[ $current_timestamp -lt $first_binding_timestamp ]]; then
add-linux-kconfig-binding --revision "$first_binding_revision"
add-linux-kconfig \
--revision "$revision" \
--architecture "$architecture" \
--kconfig-binding-file "$(output-path "$KCONFIG_BINDINGS_OUTPUT_DIRECTORY" linux "$first_binding_revision")"
else
add-linux-kconfig --revision "$revision" --architecture "$architecture"
fi
done < <(printf '%s\n' "$revisions")
}
add-linux-kconfig-history(from, to, architecture=x86) {
add-linux-system
add-linux-kconfig-revisions "$(linux-tag-revisions \
| start-at-revision "$from" \
| stop-at-revision "$to")" \
"$architecture"
}
add-linux-kconfig-sample(interval, architecture=x86) {
add-linux-system
add-linux-kconfig-revisions "$(memoize git-sample-revisions linux "$interval" master)" "$architecture"
}
# adds Linux revisions to the Linux Git repository
# creates an orphaned branch and tag for each revision
# useful to add old revisions before the first Git tag v2.6.12
# by default, tags all revisions between 2.5.45 and 2.6.12, as these use Kconfig
tag-linux-revisions(tag_option=) {
TAG_OPTION=$tag_option
add-system(system, url=) {
if [[ -z $DONE_TAGGING_LINUX ]] && [[ $system == linux ]]; then
if [[ ! -d $(input-directory)/linux ]]; then
error "Linux has not been cloned yet. Please prepend a stage that clones Linux."
fi
if git -C "$(input-directory)/linux" show-branch v2.6.11 2>&1 | grep -q "No revs to be shown."; then
git -C "$(input-directory)/linux" tag -d v2.6.11 # delete non-commit 2.6.11
fi
if [[ $TAG_OPTION != skip-tagging ]]; then
# could also tag older revisions, but none use Kconfig
tag-revisions https://mirrors.edge.kernel.org/pub/linux/kernel/v2.5/ 2.5.45
tag-revisions https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/ 2.6.0 2.6.12
# could also add more granular revisions with minor or patch level after 2.6.12, if necessary
fi
if [[ $dirty -eq 1 ]]; then
git -C "$(input-directory)/linux" prune
git -C "$(input-directory)/linux" gc
fi
DONE_TAGGING_LINUX=y
fi
}
tag-revisions(base_uri, start_inclusive=, end_exclusive=) {
local revisions
revisions=$(curl -s "$base_uri" \
| sed 's/.*>\(.*\)<.*/\1/g' | grep .tar.gz | cut -d- -f2 | sed 's/\.tar\.gz//' | sort -V \
| start-at-revision "$start_inclusive" \
| stop-at-revision "$end_exclusive")
for revision in $revisions; do
if ! git -C "$(input-directory)/linux" tag | grep -q "^v$revision$"; then
log "tag-revision: linux@$revision" "$(echo-progress add)"
local date
date=$(date -d "$(curl -s "$base_uri" | grep "linux-$revision.tar.gz" \
| cut -d'>' -f3 | tr -s ' ' | cut -d' ' -f2- | rev | cut -d' ' -f2- | rev)" +%s)
dirty=1
push "$(input-directory)"
rm-safe ./*.tar.gz*
wget -q "$base_uri/linux-$revision.tar.gz"
tar xzf ./*.tar.gz*
rm-safe ./*.tar.gz*
push linux
git reset -q --hard >/dev/null
git clean -q -dfx >/dev/null
git checkout -q --orphan "$revision" >/dev/null
git reset -q --hard >/dev/null
git clean -q -dfx >/dev/null
cp -R "../linux-$revision/." ./
git add -A >/dev/null
GIT_COMMITTER_DATE=$date git commit -q --date "$date" -m "v$revision" >/dev/null
git tag "v$revision" >/dev/null
pop
rm-safe "linux-$revision"
log "" "$(echo-done)"
else
log "" "$(echo-skip)"
fi
done
}
experiment-subjects
}
# extracts code names of linux revisions, just because it's fun :-)
read-linux-names() {
add-revision(system, revision) {
if [[ $system == linux ]]; then
log "read-linux-name: $system@$revision" "$(echo-progress read)"
if grep -q "^$system,$revision," "$(output-csv)"; then
log "" "$(echo-skip)"
return
fi
if [[ ! -d $(input-directory)/linux ]]; then
error "Linux has not been cloned yet. Please prepend a stage that clones Linux."
fi
local name
name=$({ git -C "$(input-directory)/linux" show "$revision:Makefile" | grep -oP "^NAME = \K.*"; } || true)
name=${name:-NA}
echo "$system,$revision,$name" >> "$(output-csv)"
log "" "$(echo-done)"
fi
}
echo system,revision,name > "$(output-csv)"
experiment-subjects
}
# extracts architectures of linux revisions
read-linux-architectures() {
add-revision(system, revision) {
if [[ $system == linux ]]; then
log "read-linux-architectures: $system@$revision" "$(echo-progress read)"
if grep -q "^$system,$revision," "$(output-csv)"; then
log "" "$(echo-skip)"
return
fi
if [[ ! -d $(input-directory)/linux ]]; then
error "Linux has not been cloned yet. Please prepend a stage that clones Linux."
fi
local architectures
mapfile -t architectures < <(linux-architectures "$revision")
for architecture in "${architectures[@]}"; do
echo "$system,$revision,$architecture" >> "$(output-csv)"
done
log "" "$(echo-done)"
fi
}
echo system,revision,architecture > "$(output-csv)"
experiment-subjects
}
# extracts configuration options of linux revisions
read-linux-configs() {
add-revision(system, revision) {
if [[ $system == linux ]]; then
log "read-linux-configs: $system@$revision" "$(echo-progress read)"
if grep -q "^$system,$revision," "$(output-csv)"; then
log "" "$(echo-skip)"
return
fi
if [[ ! -d $(input-directory)/linux ]]; then
error "Linux has not been cloned yet. Please prepend a stage that clones Linux."
fi
local configs config_types
configs=$(mktemp)
config_types=$(mktemp)
echo system,revision,kconfig-file,config >> "$configs"
echo system,revision,kconfig-file,config,type >> "$config_types"
linux-configs "$revision" >> "$configs"
tail -n+2 < "$configs" >> "$(output-csv)"
linux-config-types "$revision" >> "$config_types"
if [[ ! -f $(output-file types.csv) ]]; then
join-tables "$configs" "$config_types" | head -n1 > "$(output-file types.csv)"
fi
join-tables "$configs" "$config_types" | tail -n+2 >> "$(output-file types.csv)"
log "" "$(echo-done)"
rm-safe "$configs" "$config_types"
fi
}
echo system,revision,kconfig-file,config > "$(output-csv)"
experiment-subjects
}