Newer
Older
#!/bin/bash
##########################################################################
# #
# This file is part of Frama-C. #
# #
# CEA (Commissariat à l'énergie atomique et aux énergies #
# alternatives) #
# #
# you can redistribute it and/or modify it under the terms of the GNU #
# Lesser General Public License as published by the Free Software #
# Foundation, version 2.1. #
# #
# It is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU Lesser General Public License for more details. #
# #
# See the GNU Lesser General Public License version 2.1 #
# for more details (enclosed in the file licenses/LGPLv2.1). #
# #
##########################################################################
# Accept '-check' to avoid issues with ptests
while [ $# -ge 1 -a "$1" = "-check" ]; do
shift
done
if [ $# -lt 1 ]; then
echo "usage: $0 cmd [args]"
echo ""
echo " where cmd is:"
echo ""
echo " - make-template [dir]"
echo " Interactively prepares a template for running analysis scripts,"
echo " writing it to [dir/GNUmakefile]. [dir] is [.] if omitted."
echo ""
echo " - make-path"
echo " [for Frama-C developers and advanced users without Frama-C in the path]"
echo " Creates a frama-c-path.mk file in the current working directory."
echo ""
echo " - list-files [path/to/compile_commands.json]"
echo " Lists all sources in the given compile_commands.json"
echo " (defaults to './compile_commands.json' if omitted)."
echo " Also lists files defining a 'main' function"
echo " (heuristics-based; neither correct nor complete)."
echo ""
echo " - flamegraph <flamegraph.txt> [dir]"
echo " Generates flamegraph.svg and flamegraph.html in [dir]"
echo " (or in the FRAMAC_SESSION directory by default)."
echo " Also opens it in a browser, unless variable NOGUI is set."
Andre Maroneze
committed
echo ""
echo " - find-fun <function-name> [dirs]"
echo " Lists files in [dirs] declaring or defining <function-name>"
echo " (defaults to PWD + /usr/include)."
echo " Heuristics-based: neither correct nor complete."
echo ""
echo " - summary [options]"
echo " Monitors and summarizes multiple analyses dispatched by a Makefile"
echo " in the current PWD."
echo " Use $0 summary --help for more informations."
echo ""
echo " - configure <machdep>"
echo " Runs an existing configure script to only consider files"
echo " in Frama-C's libc; this will hopefully disable non-essential"
echo " and non-POSIX external libraries."
echo " <machdep> is necessary to define a required preprocessor symbol"
echo " (run 'frama-c -machdep' help to get the list of machdeps)."
echo ""
echo " - make-wrapper <target> <args>"
echo " Runs 'make <target> <args>', parsing the output to suggest"
echo " useful commands in case of failure."
echo ""
echo " - normalize-jcdb [path/to/compile_commands.json]"
echo " Applies some transformations to an existing compile_commands.json"
echo " (such as relativizing paths) to improve portability"
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
exit
fi
DIR="$( cd "$( dirname "$0" )" && pwd )"
FRAMAC_SHARE=$("${DIR}/frama-c-config" -print-share-path)
if [ -z ${FRAMAC_SESSION+x} ]; then
FRAMAC_SESSION="./.frama-c";
fi
command="$1"
# [check_path_exists path]: if [path] exists,
# ask if it should be overwritten
check_path_exists() {
if [ -e "$1" ]; then
read -p "warning: '$1' already exists. Overwrite? [y/N] " yn
case $yn in
[Yy]) ;;
*)
echo "Exiting without overwriting."
exit 0;;
esac
fi
}
# [open file]
open_file() {
case "$OSTYPE" in
cygwin*)
cmd /c start "$1"
;;
linux*)
xdg-open "$1"
;;
darwin*)
open "$1"
;;
esac
}
make_template() {
if [ "$#" -gt 0 ]; then
dir="${1%/}"
else
dir="."
fi
path="$dir/GNUmakefile"
path_tmp="${path}.tmp"
check_path_exists "$path"
read -p "Main target name: " main
if [[ ! ( "$main" =~ ^[a-zA-Z_0-9]+$ ) ]]; then
echo "error: invalid main target name";
exit 1
fi
read -p "Source files separated by spaces (default if empty: *.c): " sources
if [ "$sources" = "" ]; then
sources="*.c"
fi
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
add_main_stub=0
read -p "Add stub for function main (only needed if it uses command-line arguments)? [y/N] " yn
case $yn in
[Yy])
add_main_stub=1
sources="fc_stubs.c $sources"
;;
*)
;;
esac
sed "s/^MAIN_TARGET :=/MAIN_TARGET := ${main}/" "${FRAMAC_SHARE}/analysis-scripts/template.mk" > "$path"
sed "s|\$(MAIN_TARGET).parse:|\$(MAIN_TARGET).parse: $sources|" "$path" | sed "/# Remove these lines after defining the main target/{N;N;N;N;d;}" > "$path_tmp"; mv "$path_tmp" "$path"
if [ -e "compile_commands.json" ]; then
read -p "compile_commands.json exists, add option -json-compilation-database? [Y/n] " yn
case $yn in
[Nn])
echo "Option not added; you can later add it to FCFLAGS."
;;
*)
# the command below inserts a line after matching a given
# pattern; compatible with macOS sed
sed -e '/^FCFLAGS[[:space:]]\++=/a\
\ \ -json-compilation-database .\\' "$path" > "$path_tmp"; mv "$path_tmp" "$path"
;;
esac
fi
if [ $add_main_stub -eq 1 ]; then
check_path_exists "fc_stubs.c"
cp "${FRAMAC_SHARE}/analysis-scripts/fc_stubs.c" "./"
echo "Created stub for main function: fc_stubs.c"
sed -e '/^FCFLAGS[[:space:]]\++=/a\
\ \ -main eva_main \\' "$path" > "$path_tmp"; mv "$path_tmp" "$path"
fi
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
echo "Template created: $path"
}
make_path() {
cat <<EOF > frama-c-path.mk
FRAMAC_DIR=${DIR}
ifeq (\$(wildcard \$(FRAMAC_DIR)),)
# Frama-C not installed locally; using the version in the PATH
else
FRAMAC=\$(FRAMAC_DIR)/frama-c
FRAMAC_GUI=\$(FRAMAC_DIR)/frama-c-gui
FRAMAC_CONFIG=\$(FRAMAC_DIR)/frama-c-config
endif
EOF
echo "Wrote to: frama-c-path.mk"
}
flamegraph() {
if [ "$#" -eq 0 ]; then
echo "error: 'flamegraph' command requires a path";
exit 1
fi
if [ ! -e "$1" ]; then
echo "error: '$1' not found"
exit 1
else
path="$1"
fi
if [ "$#" -ge 2 ]; then
dir="${2%/}"
else
dir="$FRAMAC_SESSION"
fi
if [ ! -d "$dir" ]; then
mkdir "$dir"
if [ $? -ne 0 ]; then
echo "error: could not create '$dir'"
exit 1
fi
fi
out_svg="$dir/flamegraph.svg"
"${FRAMAC_SHARE}/analysis-scripts/flamegraph.pl" \
--title "Eva Flamegraph" --inverted --hash "$path" \
--width 1400 --fontsize 11 > "$out_svg.tmp"
if [ ! $? -eq 0 ]; then
echo "Error creating flamegraph, aborting."
exit 1
fi
mv "$out_svg.tmp" "$out_svg"
out_html="$dir/flamegraph.html"
cat <<EOF > "$out_html"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Eva Flamegraph</title>
</head>
<body>
<embed src="flamegraph.svg" style="max-width:100%;width:1400px;min-width:1000px">
</body>
</html>
EOF
if [ -z "$NOGUI" ]; then
open_file "$out_html"
fi
}
configure_for_frama_c() {
if [ "$#" -eq 0 ]; then
echo "error: 'configure' command requires a machdep";
exit 1
fi
MACHDEP="$(echo $1 | tr a-z A-Z)"
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
shift
CPP="gcc -E -nostdinc -fno-builtin -I${FRAMAC_SHARE}/libc -D__FC_MACHDEP_${MACHDEP}" ./configure "$@"
}
normalize_jcdb() {
path=""
if [ "$#" -eq 0 ]; then
path="./compile_commands.json"
else
path="$1"
fi
if [ ! -e "$path" ]; then
echo "error: cannot find file: $path";
exit 1
fi
sed "s|$PWD/||g" "$path" > "${path}.tmp"
cmp -s "$path" "${path}.tmp"
if [ $? -eq 0 ]; then
echo "No changes to be applied to $path"
rm "${path}.tmp"
else
echo "Differences to be applied to $path:"
diff -u0 "$path" "${path}.tmp"
read -p "Normalize $path? [y/N] " yn
case $yn in
[Yy])
mv "${path}.tmp" "$path"
echo "Normalization applied to $path"
;;
*)
echo "Exiting without overwriting."
exit 0;;
esac
fi
case "$command" in
"make-template")
shift;
make_template "$@";
;;
"make-path")
shift;
make_path;
;;
"list-files")
shift;
${FRAMAC_SHARE}/analysis-scripts/list_files.py "$@";
;;
Andre Maroneze
committed
"find-fun")
shift;
${FRAMAC_SHARE}/analysis-scripts/find_fun.py "$@";
;;
"flamegraph")
shift;
flamegraph "$@";
;;
"summary")
shift;
${FRAMAC_SHARE}/analysis-scripts/summary.py "$@";
;;
"configure")
shift;
configure_for_frama_c "$@";
;;
"make-wrapper")
shift;
${FRAMAC_SHARE}/analysis-scripts/make_wrapper.py "$0" "$@";
;;
"normalize-jcdb")
shift;
normalize_jcdb "$@";
;;
*)
echo "error: unrecognized command: $command"
esac