diff options
Diffstat (limited to 'FreeRTOS/Test/VeriFast/scripts')
-rwxr-xr-x | FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh | 3 | ||||
-rw-r--r-- | FreeRTOS/Test/VeriFast/scripts/callgraph.md | 20 | ||||
-rwxr-xr-x | FreeRTOS/Test/VeriFast/scripts/callgraph.py | 83 | ||||
-rw-r--r-- | FreeRTOS/Test/VeriFast/scripts/diff_files.md | 40 | ||||
-rwxr-xr-x | FreeRTOS/Test/VeriFast/scripts/extract.py | 73 | ||||
-rwxr-xr-x | FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh | 47 |
6 files changed, 266 insertions, 0 deletions
diff --git a/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh b/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh new file mode 100755 index 000000000..3384ea1aa --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/annotation_overhead.sh @@ -0,0 +1,3 @@ +#!/bin/bash -eu + +NO_COVERAGE=1 EXTRA_VERIFAST_ARGS=-stats make queue | grep overhead: | sort | uniq diff --git a/FreeRTOS/Test/VeriFast/scripts/callgraph.md b/FreeRTOS/Test/VeriFast/scripts/callgraph.md new file mode 100644 index 000000000..5316a6121 --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/callgraph.md @@ -0,0 +1,20 @@ +# Generate callgraph + +## Requirements + + - python3 + - pycparser + - graphviz/dot + - [inconsolata](https://fonts.google.com/specimen/Inconsolata) + +## Instructions + +``` +cd scripts +git clone https://github.com/eliben/pycparser.git #< you need this for pycparser's libc headers even if pycparser is installed +mkdir fake_include +touch fake_include/threading.h +gcc -E -I pycparser/utils/fake_libc_include/ -I ../include/ -I fake_include/ ../queue/*.c > out.pp +./callgraph.py > out.dot +dot -Nfontname=inconsolata -Tpng -o callgraph.png out.dot +``` diff --git a/FreeRTOS/Test/VeriFast/scripts/callgraph.py b/FreeRTOS/Test/VeriFast/scripts/callgraph.py new file mode 100755 index 000000000..ca6fa4ee8 --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/callgraph.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +from __future__ import print_function +from pycparser import c_parser, c_ast, parse_file +import sys + +ignore_callee = set(['mutex_acquire', 'mutex_release']) +ignore_caller = set(['caller_reinstates_queue_predicate']) +proven = [ + 'prvCopyDataFromQueue', + 'prvCopyDataToQueue', + 'prvInitialiseNewQueue', + 'prvIsQueueEmpty', + 'prvIsQueueFull', + 'prvLockQueue', + 'prvUnlockQueue', + 'uxQueueMessagesWaiting', + 'uxQueueSpacesAvailable', + 'vQueueDelete', + 'xQueueGenericCreate', + 'xQueueGenericReset', + 'xQueueGenericSend', + 'xQueueGenericSendFromISR', + 'xQueueIsQueueEmptyFromISR', + 'xQueueIsQueueFullFromISR', + 'xQueuePeek', + 'xQueuePeekFromISR', + 'xQueueReceive', + 'xQueueReceiveFromISR', +] + +modeled = [ + 'setInterruptMask', + 'clearInterruptMask', + 'setInterruptMaskFromISR', + 'clearInterruptMaskFromISR', + 'vTaskSuspendAll', + 'xTaskResumeAll', +] + +CALLMAP = set() + + +class FuncCallVisitor(c_ast.NodeVisitor): + def __init__(self, caller): + self.caller = caller + + def visit_FuncCall(self, node): + callee = node.name.name + if callee not in ignore_callee: + CALLMAP.add((node.name.name, self.caller)) + + +class FuncDefVisitor(c_ast.NodeVisitor): + def visit_FuncDef(self, node): + caller = node.decl.name + if caller in ignore_caller: + return + if caller.startswith('wrapper_'): + caller = caller[8:] + v = FuncCallVisitor(caller) + v.visit(node) + + +def show_func_calls(filename): + ast = parse_file(filename, use_cpp=False) + v = FuncDefVisitor() + v.visit(ast) + + +if __name__ == "__main__": + filename = 'out.pp' + show_func_calls(filename) + print('digraph G {') + print(' rankdir=LR;') + print(' node [style = filled, colorscheme = set13;];') + for f in proven: + print(' %s [fillcolor = 3];' % f) + for f in modeled: + print(' %s [fillcolor = 2];' % f) + for (callee, caller) in CALLMAP: + print(' %s -> %s;' % (callee, caller)) + print('}') diff --git a/FreeRTOS/Test/VeriFast/scripts/diff_files.md b/FreeRTOS/Test/VeriFast/scripts/diff_files.md new file mode 100644 index 000000000..59f62d364 --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/diff_files.md @@ -0,0 +1,40 @@ +# Generate diffs between FreeRTOS source and proofs + +## Requirements + + - python3 + - ctags 5.8 + - diff 3.4+ + - [diff2html](https://diff2html.xyz/) + +## Instructions + +The following will extract per-function files from the original FreeRTOS source +implementation and the proof directory. + + +``` +cd scripts +./generate_diff_files.sh +# will extract to ./FreeRTOS-Kernel/generated and ./queue/generated +``` + +Then use `diff` for a side-by-side comparison. Note that the `--color=always` +flag needs v3.4+: + +``` +diff --color=always --width=$COLUMNS --suppress-common-lines --side-by-side FreeRTOS-Kernel/generated queue/generated | less -r +``` + +Or generate a html report using `diff2html`: + +``` +diff -u FreeRTOS-Kernel/generated queue/generated | diff2html -i stdin +``` + +The expectation is that the proofs make minimal changes to the original source +implementation in the form of: + + - VeriFast annotations `/*@...@*/` and `//*...` + - Additional comments explaining the proof `/*...*/` + - Flagged changes within `#if[n]def VERIFAST` diff --git a/FreeRTOS/Test/VeriFast/scripts/extract.py b/FreeRTOS/Test/VeriFast/scripts/extract.py new file mode 100755 index 000000000..0b74d79a9 --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/extract.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +from __future__ import print_function +import sys +from enum import Enum + + +class Extractor(object): + @staticmethod + def __parse_ctags(tags_filename): + def convert_excmd(excmd): + assert excmd.endswith(';"') + linenum = excmd[:-2] # remove ';"' + return int(linenum) + result = {} + with open(tags_filename) as f: + for line in f: + if line.startswith('!'): + continue + parts = line.split('\t') + funcname = parts[0] + funcfile = parts[1] + linenum = convert_excmd(parts[2]) + result[funcname] = (funcfile, linenum) + return result + + def __init__(self, tags_filename): + self.map = Extractor.__parse_ctags(tags_filename) + + class State(Enum): + INIT = 0 + HEAD = 1 + BODY = 2 + + def text_of_funcname(self, funcname): + if funcname not in self.map: + return [] + funcfile, linenum = self.map[funcname] + result = [] + state, bracecount = Extractor.State.INIT, 0 + with open(funcfile) as f: + for i, line in enumerate(f, start=1): # ctags counts linenums from 1 + if state == Extractor.State.INIT and linenum <= i: + state = Extractor.State.HEAD + if state == Extractor.State.HEAD: + result.append(line) + lbrace = line.count('{') + rbrace = line.count('}') + bracecount += lbrace + bracecount -= rbrace + if '{' in line: + state = Extractor.State.BODY + continue + if state == Extractor.State.BODY: + result.append(line) + lbrace = line.count('{') + rbrace = line.count('}') + bracecount += lbrace + bracecount -= rbrace + if bracecount == 0: + break + return result + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: %s <tagfile> <funcname>" % sys.argv[0]) + sys.exit(1) + tag_filename = sys.argv[1] + funcname = sys.argv[2] + extractor = Extractor('tags') + result = extractor.text_of_funcname(funcname) + print(''.join(result)) + sys.exit(0) diff --git a/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh b/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh new file mode 100755 index 000000000..55f9cfbd2 --- /dev/null +++ b/FreeRTOS/Test/VeriFast/scripts/generate_diff_files.sh @@ -0,0 +1,47 @@ +#!/bin/bash -eu + +FUNCS=( + prvCopyDataFromQueue + prvCopyDataToQueue + prvInitialiseNewQueue + prvIsQueueEmpty + prvIsQueueFull + prvUnlockQueue + uxQueueMessagesWaiting + uxQueueSpacesAvailable + vQueueDelete + xQueueGenericCreate + xQueueGenericReset + xQueueGenericSend + xQueueGenericSendFromISR + xQueueIsQueueEmptyFromISR + xQueueIsQueueFullFromISR + xQueuePeek + xQueuePeekFromISR + xQueueReceive + xQueueReceiveFromISR +) + +if [ ! -d "FreeRTOS-Kernel" ]; then + git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git +fi +pushd FreeRTOS-Kernel > /dev/null +rm -rf tags generated +ctags --excmd=number queue.c +mkdir generated +for f in ${FUNCS[@]}; do + ../extract.py tags $f > generated/$f.c +done +popd > /dev/null +echo "created: FreeRTOS-Kernel/generated" + +ln -fs ../queue . +pushd queue > /dev/null +rm -rf tags generated +ctags --excmd=number *.c +mkdir generated +for f in ${FUNCS[@]}; do + ../scripts/extract.py tags $f > generated/$f.c +done +popd > /dev/null +echo "created: queue/generated" |