All Rights Reserved. The contents of this document cannot be reproduced without prior permission of the authors. Building Embedded Systems Chapter 5: Maintenance and Debugging Andreas Knirsch andreas.knirsch@h-da.de
Building Embedded Systems Chapter 5: Maintenance and Debugging Code Analysis Identify problems before they occur.
Static Code Check Check for compliance with certain coding standards and software metrics (e.g. complexity, nesting depth, comments). Can be performed without user interaction. Provides hints where to take a closer look. Tools: e.g. gcc, eclipse, coverity
Dynamic Code Check Software is checked during runtime. Code needs to be compiled and run. Effort depends on system complexity (and e.g. user input, system interaction) Check affects execution time (potential violation of temporal behavior) Tools: e.g. Valgrind, insure++, mudflap
Valgrind framework for debugging and profiling tools open-source optimized for C/C++ console based graphical UI available: Valkyrie indicates erroneous/suspicious code lines observes usage of (dynamic) memory unable to detect e.g. erroneous control flow
Some Valgrind Tools memcheck (default) e.g. out-of-bounds access, use uninitialized variables, dealloc unallocated memory, mismatched free/delete cachegrind analyze cache hits/misses to allow optimization massif generates regular snapshots of the heap usage helgrind (beta) a thread debugger that finds non-synced memory access To choose a tool, call Valgrind with arguments: shell> valgrind -tool=<tool>...
Valgrind Example example.c #include <stdlib.h> #include <stdio.h> void f(int x) { printf("x=%d\n", x) ; } int main( void ) { int n; int* x = malloc(10*sizeof(int)); x[10] = 0; f(n); return 0; } you already know GNU Make :-) Makefile example: example.c gcc -g Wall o $@ $^ run: example./$^ valgrind: example $@./$^ shell>> make run./example x=1649016926 # compile (if necessary) and run example Our program compiles and runs without error :-)
Valgrind Example (II) #include <stdlib.h> #include <stdio.h> void f(int x) { printf("x=%d\n", x) ; } int main( void ) { int n; int* x = malloc(10*sizeof(int)); x[10] = 0; f(n); return 0; } shell>> make valgrind # run memcheck ERROR SUMMARY: 4 errors a b c Invalid write of size 4. Conditional jump or move depends on uninitialised value(s). Use of uninitialised value of size 8. Conditional jump or move depends on uninitialised value(s). Heap: in use at exit: 40 bytes in 1 blocks Leak: definitely lost 40 bytes in 1 blocks
Code Check Improve software quality. Static checks are cheap and easy. Dynamic checks can be difficult but still worth to do (e.g. check isolated modules might be easier). Should be done on a regular base. Are a good starting point for software reviews.
References [Wietzke, 2012] Wietzke, J.: Embedded Technologies. Springer, 2012.
All Rights Reserved. The contents of this document cannot be reproduced without prior permission of the authors. Building Embedded Systems Chapter 5: Maintenance and Debugging Andreas Knirsch andreas.knirsch@h-da.de