Am Wed, 12 Apr 2017 13:38:50 +0200
schrieb Henning Schild <[email protected]>:

> With the new feature to download the used firmware out of sysfs and
> a way to get GCOV data into that. It is now time to extract this
> information and generate .gcda files for higher level tools to work
> with.
> Instead of dealing with the details of that just use what the
> compiler gives us when we link to its gcov lib.
> 
> Signed-off-by: Henning Schild <[email protected]>
> 
> diff --git a/.gitignore b/.gitignore
> --- a/.gitignore
> +++ b/.gitignore
> @@ -4,6 +4,7 @@
>  *.cmd
>  *.bin
>  *.gcno
> +*.gcda
>  .tmp_versions
>  *.dtb
>  *.dtb.S
> @@ -14,6 +15,7 @@ driver/jailhouse.ko
>  hypervisor/include/jailhouse/config.h
>  hypervisor/hypervisor.lds
>  tools/jailhouse
> +tools/jailhouse-gcov-extract
>  tools/jailhouse-config-collect
>  configs/*.cell
>  Documentation/generated
> diff --git a/tools/Makefile b/tools/Makefile
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -1,7 +1,7 @@
>  #
>  # Jailhouse, a Linux-based partitioning hypervisor
>  #
> -# Copyright (c) Siemens AG, 2013-2016
> +# Copyright (c) Siemens AG, 2013-2017
>  #
>  # Authors:
>  #  Jan Kiszka <[email protected]>
> @@ -23,6 +23,7 @@ LDFLAGS :=
>  GCOV_PROFILE := n
>  
>  BINARIES := jailhouse
> +
>  HELPERS := \
>       jailhouse-cell-linux \
>       jailhouse-cell-stats \
> @@ -58,6 +59,17 @@ targets += jailhouse.o
>  $(obj)/jailhouse: $(obj)/jailhouse.o
>       $(call if_changed,ld)
>  
> +CFLAGS_jailhouse-gcov-extract.o      :=
> -I$(src)/../hypervisor/include \
> +     -I$(src)/../hypervisor/arch/$(SRCARCH)/include
> +# just change ldflags not cflags, we are not profiling the tool
> +LDFLAGS_jailhouse-gcov-extract := -lgcov -fprofile-arcs
> +
> +targets += jailhouse-gcov-extract.o
> +always += jailhouse-gcov-extract
> +
> +$(obj)/jailhouse-gcov-extract: $(obj)/jailhouse-gcov-extract.o
> +     $(call if_changed,ld)
> +
>  $(obj)/jailhouse-config-collect: $(src)/jailhouse-config-create
> $(src)/jailhouse-config-collect.tmpl $(call if_changed,gen_collect)
>  
> diff --git a/tools/jailhouse-gcov-extract.c
> b/tools/jailhouse-gcov-extract.c new file mode 100644
> --- /dev/null
> +++ b/tools/jailhouse-gcov-extract.c
> @@ -0,0 +1,217 @@
> +/*
> + * Jailhouse, a Linux-based partitioning hypervisor
> + *
> + * Copyright (c) Siemens AG, 2017
> + *
> + * Authors:
> + *  Henning Schild <[email protected]>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.
> See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <error.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <jailhouse/header.h>
> +#include <asm/jailhouse_header.h>
> +
> +#if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
> +#error "Gcov format of gcc < 4.7 is not supported!"
> +#endif
> +
> +/*
> + * the following bits are heavily inspired by
> linux/kernel/gcov/gcc_4.7.c
> + * with some slight modification
> + */
> +#if BITS_PER_LONG >= 64

This was never defined, fixed that.

> +typedef long gcov_type;
> +#else
> +typedef long long gcov_type;
> +#endif
> +
> +#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
> +#define GCOV_COUNTERS                        10
> +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
> +#define GCOV_COUNTERS                        9
> +#else
> +#define GCOV_COUNTERS                        8
> +#endif
> +
> +struct gcov_ctr_info {
> +     unsigned int num;
> +     gcov_type *values;
> +};
> +
> +struct gcov_fn_info {
> +     struct gcov_info *key;
> +     unsigned int ident;
> +     unsigned int lineno_checksum;
> +     unsigned int cfg_checksum;
> +     struct gcov_ctr_info ctrs[0];
> +};
> +
> +struct gcov_info {
> +     unsigned int version;
> +     struct gcov_info *next;
> +     unsigned int stamp;
> +     char *filename;
> +     void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
> +     unsigned int n_functions;
> +     struct gcov_fn_info **functions;
> +};
> +/*
> + * end of linux/kernel/gcov/gcc_4.7.c
> + */
> +
> +static void *hypervisor;
> +static ssize_t hypervisor_size;
> +extern void __gcov_merge_add(gcov_type *counters, unsigned int
> n_counters); +extern void __gcov_init(struct gcov_info *);
> +extern void __gcov_dump();
> +
> +static void *hypervisor2current(void *hvp)
> +{
> +     unsigned long hvaddr = (unsigned long)hvp;
> +     void *ret;
> +
> +     if(hvp == NULL)
> +             return NULL;
> +     assert(hvaddr >= JAILHOUSE_BASE &&
> +            hvaddr < JAILHOUSE_BASE + hypervisor_size);
> +     ret = (void *)(hvaddr - JAILHOUSE_BASE + (unsigned
> long)hypervisor); +
> +     return ret;
> +}
> +
> +/*
> + * translate one gcov-"tree" from the hypervisor address space to
> the current
> + * addresses
> + */
> +static void translate_all_pointers(struct gcov_info *info)
> +{
> +     struct gcov_fn_info *fn_info;
> +     struct gcov_ctr_info *ctr_info;
> +     unsigned int i, j, active;
> +
> +     info->next = hypervisor2current(info->next);
> +     info->filename = hypervisor2current(info->filename);
> +     active = 0;
> +     for (i = 0; i < GCOV_COUNTERS; i++) {
> +             if (info->merge[i]) {
> +                     active++;
> +                     info->merge[i] = &__gcov_merge_add;
> +             } else
> +                     break;
> +     }
> +     info->functions = hypervisor2current(info->functions);
> +     for (i = 0; i < info->n_functions; i++) {
> +             info->functions[i] =
> hypervisor2current(info->functions[i]);
> +             fn_info = info->functions[i];
> +             if (fn_info) {
> +                     fn_info->key =
> hypervisor2current(fn_info->key);
> +                     assert(fn_info->key == info);
> +                     for (j = 0; j < active; j++) {
> +                             ctr_info = fn_info->ctrs + j;
> +                             ctr_info->values =
> +
> hypervisor2current(ctr_info->values);
> +                     }
> +             }
> +     }
> +}
> +
> +int main(int argc, char **argv)
> +{
> +     struct gcov_info *gcov_info_head, *info, *next;
> +     struct jailhouse_header *header;
> +     struct stat sbuf;
> +     char *filename;
> +     char *errstr = NULL;
> +     ssize_t count, ret;
> +     int fd;
> +
> +     if (argc == 1) {
> +             filename = "/sys/devices/jailhouse/core";
> +     } else {
> +             if (argc != 2 || (strncmp(argv[1], "-", 1) == 0)) {
> +                     printf("Usage: %s [-h] [FILE]\n", argv[0]);
> +                     if (strcmp(argv[1], "-h")) {
> +                             errno = EINVAL;
> +                             errstr = argv[1];
> +                     }
> +                     goto out;
> +             }
> +             filename = argv[1];
> +     }
> +     fd = open(filename, O_RDONLY);
> +     if (fd < 1) {
> +             errstr = filename;
> +             goto out;
> +     }
> +
> +     ret = fstat(fd, &sbuf);
> +     if (ret) {
> +             errstr = filename;
> +             goto out;
> +     }
> +     hypervisor_size = sbuf.st_size;
> +     hypervisor = malloc(hypervisor_size);
> +     if (hypervisor == NULL) {
> +             errstr = "malloc";
> +             goto out_f;
> +     }
> +
> +     count = 0;
> +     while (count < hypervisor_size) {
> +             ret = read(fd, hypervisor + count,
> hypervisor_size-count);
> +             if (ret < 0 && errno != EINTR) {
> +                     errstr = "read";
> +                     goto out_m;
> +             }
> +             count += ret;
> +     }
> +     assert(count == hypervisor_size);
> +
> +     header = (struct jailhouse_header *)hypervisor;
> +     if (strcmp(header->signature, JAILHOUSE_SIGNATURE)) {
> +             errno = EINVAL;
> +             error(0, 0, "%s does not seem to be a hypervisor
> image",
> +                   filename);
> +             goto out_m;
> +     }
> +
> +     gcov_info_head = hypervisor2current(header->gcov_info_head);
> +     if (!gcov_info_head) {
> +             errno = EINVAL;
> +             error(0, 0, "%s does not contain gcov information.",
> filename);
> +             goto out_m;
> +     }
> +     info = gcov_info_head;
> +     for (info = gcov_info_head; info; info = info->next)
> +             translate_all_pointers(info);
> +
> +     for (info = gcov_info_head; info;) {
> +             /* remember next because __gcov_init changes it */
> +             next = info->next;
> +             __gcov_init(info);
> +             info = next;
> +     }
> +     __gcov_dump();
> +
> +out_m:
> +     free(hypervisor);
> +out_f:
> +     close(fd);
> +out:
> +     if (errno && errstr)
> +             error(errno, errno, errstr);
> +     return 0;
> +}

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to