Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce lib-embedded-gcov #1

Open
wants to merge 1 commit into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Config.uk
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
menuconfig LIBEMBEDDEDGCOV
bool "embedded-gcov"
default n

if LIBEMBEDDEDGCOV
config LIBEMBEDDEDGCOV_PROVIDE_CALL_CONSTRUCTORS
bool "Provide call constructors"
help
In most systems __gcov_init() is called on startup. If you are
running on a non-standard startup environment you can enable this
option, and gcov-embedded will provide __gcov_call_constructors()
that you can run manually. For that you will need to define __ctor_list
and __ctor_end. For more info refer to the embedded-gcov documentation.
default n

config LIBEMBEDDEDGCOV_PRINT_STATUS
bool "Print status to console"
help
Print status and error messages to the serial console. If the
coverage data output is set to console, status is always printed
to the console.
default n

config LIBEMBEDDEDGCOV_USE_MALLOC
bool "Use malloc"
depends on LIBUKALLOC
help
Use malloc to get space for coverage data"
default y

choice LIBEMBEDDEDGCOV_OUTPUT
prompt "Coverage data output"
default LIBEMBEDDEDGCOV_OUTPUT_SERIAL_HEXDUMP
config LIBEMBEDDEDGCOV_OUTPUT_SERIAL_HEXDUMP
bool "Console"
endchoice

endif
78 changes: 78 additions & 0 deletions Makefile.uk
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# SPDX-License-Identifier: BSD-3-Clause
#
# embedded-gcov Makefile.uk
#
# Authors: Michalis Pappas <[email protected]>
#
# Copyright (c) 2023, Unikraft GmbH
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
################################################################################
# App registration
################################################################################
$(eval $(call addlib,libembeddedgcov,$(CONFIG_LIBEMBEDDEDGCOV)))

################################################################################
# Sources
################################################################################
LIBEMBEDDEDGCOV_BRANCH = main
LIBEMBEDDEDGCOV_URL = https://github.com/nasa-jpl/embedded-gcov.git
LIBEMBEDDEDGCOV_PATCHDIR = $(LIBEMBEDDEDGCOV_BASE)/patches
$(eval $(call clone,libembeddedgcov,$(LIBEMBEDDEDGCOV_URL),$(LIBEMBEDDEDGCOV_BRANCH)))
$(eval $(call patch,libembeddedgcov,$(LIBEMBEDDEDGCOV_PATCHDIR),$(LIBEMBEDDEDGCOV_BASENAME)))

################################################################################
# Library sources
################################################################################
LIBEMBEDDEDGCOV_SRCS-y += $(LIBEMBEDDEDGCOV_ORIGIN)/code/gcov_public.c
LIBEMBEDDEDGCOV_SRCS-y += $(LIBEMBEDDEDGCOV_ORIGIN)/code/gcov_gcc.c
LIBEMBEDDEDGCOV_SRCS-y += $(LIBEMBEDDEDGCOV_ORIGIN)/code/gcov_printf.c

################################################################################
# Library includes
################################################################################
CINCLUDES-$(CONFIG_LIBEMBEDDEDGCOV) += -I$(LIBEMBEDDEDGCOV_ORIGIN)/code
CXXINCLUDES-$(CONFIG_LIBEMBEDDEDGCOV) += -I$(LIBEMBEDDEDGCOV_ORIGIN)/code

################################################################################
# Library flags
################################################################################

CFLAGS-$(CONFIG_LIBEMBEDDEDGCOV) += -ftest-coverage -fprofile-arcs

ifneq ($(CONFIG_LIBEMBEDDEDGCOV_OUTPUT_BINARY_FILE),)
$(error Binary file output not implemented)
endif
ifneq ($(CONFIG_LIBEMBEDDEDGCOV_OUTPUT_BINARY_MEMORY),)
$(error Memory output not implemented)
endif

LIBEMBEDDEDGCOV_CFLAGS-y += -Dgcov_printf=printf
LIBEMBEDDEDGCOV_CFLAGS-$(CONFIG_LIBEMBEDDEDGCOV_OUTPUT_SERIAL_HEXDUMP) += -DGCOV_OPT_OUTPUT_SERIAL_HEXDUMP
LIBEMBEDDEDGCOV_CFLAGS-$(CONFIG_LIBEMBEDDEDGCOV_PRINT_STATUS) += -DGCOV_OPT_PRINT_STATUS
LIBEMBEDDEDGCOV_CFLAGS-$(CONFIG_LIBEMBEDDEDGCOV_PROVIDE_CALL_CONSTRUCTORS) += -DGCOV_OPT_PROVIDE_CALL_CONSTRUCTORS
LIBEMBEDDEDGCOV_CFLAGS-$(CONFIG_LIBEMBEDDEDGCOV_USE_MALLOC) += -DGCOV_OPT_USE_MALLOC
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,64 @@
# lib-embedded-gcov
Coverage suppport

Unikraft port of [embedded-gcov](https://github.com/nasa-jpl/embedded-gcov).

## Step-by-step Instructions

Here you can find step-by-step instructions on obtaining coverage information for a Unikraft application.

For more information, see the documentation provided by [embedded-gcov](https://github.com/nasa-jpl/embedded-gcov).

### Step 1: Prepare the application

Initialization of gcov is done transparently to the application. `lib-embedded-gcov` adds the required GCC options for coverage, and at runtime, `__gcov_init()` is automatically called when Unikraft boots via constructors. Therefore no changes are required for initialization. However, if coverage collection must start at a later point, one can modify the application to call `gcov_clear_counters()` manually.

On the other hand, it is necessary to modify the application to call `__gcov_exit()` manually. This function causes `lib-embedded-gcov` to gather and output coverage information using the selected output method.

### Step 2: Select output method

In the `embedded-gcov` section of Kconfig, select the output method to use:
- `Console`: Writes coverage data to console output.
- `File`: Writes coverage data to a binary file.
- `Memory`: Writes coverage data into memory.

### Step 3: Run the application

**Console output:**
On QEMU, you can obtain the console output by passing the `logfile` parameter to the character device that implements the serial output:
```
-chardev stdio,id=char0,logfile=serial.log,signal=off -serial chardev:char0
```
*NOTE*: It is essential not to use `-nographic` option here because that clashes with the redirection of standard output.

This QEMU run will dump console output into a text file named `serial.log`.

### Step 4: Generate coverage report

You must process the output to obtain coverage results in a pleasant viewing fashion. `lib-embedded-gcov` provides the `gcov_process.sh` script for that, which is essentially a wrapper around the tools provided by `embedded-gcov`.

Before executing the script below make sure you have the required dependencies installed, that is:
- `dox2unix`
- `lcov`

With the dependencies installed, invoke `gcov_process.sh` with parameters depending on the output method selected.

**Console output:**
```bash
lib-embedded-gcov/scripts/gcov_process.sh -c <console_output> <build_directory>
```

**Binary file / Memory output:**
```bash
lib-embedded-gcov/scripts/gcov_process.sh -b <binary_output> <build_directory>
```

`gcov_process.sh` will generate a lcov report and provide a link, as shown below:
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three backticks are here by mistake, right?

...
Writing directory view page.
Overall coverage rate:
lines......: 29.8% (2345 of 7858 lines)
functions..: 36.3% (228 of 628 functions)

lcov report in file:///tmp/uk_embedded-gcov/app-helloworld/build/libembeddedgcov/origin/results/html/index.html
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
From 51043fb1ad5b99a66749bce2661b388e26b6f90f Mon Sep 17 00:00:00 2001
From: michpappas <[email protected]>
Date: Sat, 21 Jan 2023 18:11:26 +0100
Subject: [PATCH] Disable all user options to allow controlling via KConfig

---
code/gcov_public.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/code/gcov_public.h b/code/gcov_public.h
index 0982c2c..9a32a8c 100644
--- a/code/gcov_public.h
+++ b/code/gcov_public.h
@@ -51,7 +51,7 @@
* If defined, you must also provide defs below
* for GCOV_PRINT_STR and GCOV_PRINT_NUM.
*/
-#define GCOV_OPT_PRINT_STATUS
+//#define GCOV_OPT_PRINT_STATUS

/* Reset watchdog timeout during gcov tree scanning.
* Might be needed if you enable serial output on a slow port,
@@ -95,7 +95,7 @@ extern void *__ctor_end;
* You might NOT want this if you are extremely memory constrained
* (such as in PROM) and do not need this function to take up some bytes.
*/
-#define GCOV_OPT_PROVIDE_CLEAR_COUNTERS
+//#define GCOV_OPT_PROVIDE_CLEAR_COUNTERS

/* Provide small imitation printf function.
* This is only needed if you want serial port outputs and
@@ -104,7 +104,7 @@ extern void *__ctor_end;
* write_bytes() that does the actual serial output in your system.
* See gcov_printf.c
*/
-#define GCOV_OPT_PROVIDE_PRINTF_IMITATION
+//#define GCOV_OPT_PROVIDE_PRINTF_IMITATION

/* select data output method(s) ------------------------------------ */

@@ -122,7 +122,7 @@ extern void *__ctor_end;

/* Modify this output filename if desired */
/* Not used if you do not define GCOV_OPT_OUTPUT_BINARY_FILE */
-#define GCOV_OUTPUT_BINARY_FILENAME "gcov_output.bin"
+//#define GCOV_OUTPUT_BINARY_FILENAME "gcov_output.bin"

/* Modify file headers, data type and functions, if needed */
/* Not used if you do not define GCOV_OPT_OUTPUT_BINARY_FILE */
@@ -164,7 +164,7 @@ typedef FILE * GCOV_FILE_TYPE;
* for GCOV_PRINT_STR and GCOV_PRINT_NUM.
* Can be combined with other GCOV_OPT_OUTPUT_* options.
*/
-#define GCOV_OPT_OUTPUT_SERIAL_HEXDUMP
+//#define GCOV_OPT_OUTPUT_SERIAL_HEXDUMP

/* Function to print a string without newline.
* Not used if you don't define either GCOV_OPT_PRINT_STATUS
--
2.25.1

29 changes: 29 additions & 0 deletions patches/0002-Use-consistent-types.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
From a3e60bce495397005c093a2a905b65e0baabdbee Mon Sep 17 00:00:00 2001
From: Michalis Pappas <[email protected]>
Date: Mon, 8 May 2023 09:08:09 +0200
Subject: [PATCH] Use consistent types

Replace UINT32 in the function declaration of __gcov_call_constructors
with u32 which is used in the rest of the codebase.

Signed-off-by: Michalis Pappas <[email protected]>
---
code/gcov_public.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/code/gcov_public.c b/code/gcov_public.c
index 94aaff4..98e6fc5 100644
--- a/code/gcov_public.c
+++ b/code/gcov_public.c
@@ -203,7 +203,7 @@ void __gcov_call_constructors(void) {
while (ctor != &__ctor_end) {
void (*func)(void);

- func = (void ( *)(void))(*(UINT32 *)ctor);
+ func = (void ( *)(void))(*(u32 *)ctor);

func();
ctor++;
--
2.34.1

39 changes: 39 additions & 0 deletions scripts/gcov_process.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash
set -e

if [[ $# -ne 2 ]]; then
echo "Usage: $0 <build_dir> <console_dump>"
exit
fi

if [ -n "${CROSS_COMPILE}" ]; then
GCOV=${CROSS_COMPILE}/gcov
else
GCOV=$(which gcov)
fi

if [ -z "$GCOV" ]; then
echo "$0: Could not find gcov"
exit
fi

BUILD_DIR=$(realpath $1)
CONSOLE_DUMP=$(realpath $2)
GCOV_DIR=${BUILD_DIR}/libembeddedgcov/origin/

cd ${GCOV_DIR}/scripts

rm -rf ../objs/*
rm -rf ../results/*

find $BUILD_DIR -type d -name objs -prune -o -name \*.gcno -exec cp {} ../objs/ \;

lcov --gcov-tool ${CROSS_COMPILE}gcov --capture --initial \
--directory ../objs/ -o ../results/baseline.info

./gcov_convert.sh $CONSOLE_DUMP
./lcov_newcoverage.sh
./lcov_combine_new_base.sh
./genhtml_report.sh

echo -e "\nlcov report in file://$(realpath ../results/html)/index.html\n"