...
 
Commits (7)
......@@ -18,9 +18,9 @@ endif
# Build up our settings from our inputs and our environment
LEON ?= leon3
RTEMS ?= /opt/rtems-4.11-2016.04.01.${FPU_SUFFIX}
RTEMS_MAKEFILE_PATH = ${RTEMS}/sparc-rtems4.11/${LEON}
CROSS_PREFIX ?= sparc-rtems4.11
RTEMS_MAKEFILE_PATH = ${RTEMS}/${CROSS_PREFIX}/${LEON}
RTEMS_LIB=${RTEMS_MAKEFILE_PATH}/lib
CROSS_PREFIX=sparc-rtems4.11
# If not selected, compile debug version of binary (no optimizations)
#ifeq ($(CFG),)
......@@ -38,12 +38,21 @@ VPATH=src
# DEAR USER, YOU MUST EDIT THIS
SRC= \
init.c \
common.c \
task1.c \
task2.c \
common.c \
memcheck.c
SUFFIX=$(CFG).$(FPU_SUFFIX).$(LEON)
ifeq ($(COVERAGE),1)
SRC += \
base.c \
gcc_4_7.c
COVERAGE_SUFFIX=WITH_COVERAGE
else
COVERAGE_SUFFIX=NO_COVERAGE
endif
SUFFIX=$(CFG).$(FPU_SUFFIX).$(LEON).$(COVERAGE_SUFFIX)
# Build a Dependency list and an Object list, by replacing the .c
# extension to .d for dependency files, and .o for object files.
......@@ -65,7 +74,7 @@ INCLUDEFLAGS= -I src
# Compilation flags (common)
COMMON += -B${RTEMS_LIB} -specs bsp_specs -qrtems \
-mcpu=cypress -DBSP_${LEON} \
-mcpu=leon3 -DBSP_${LEON} \
-ffunction-sections -fdata-sections -Wall \
-Wmissing-prototypes -Wimplicit-function-declaration \
-Wstrict-prototypes -Wnested-externs
......@@ -77,6 +86,14 @@ else
CFLAGS += ${COMMON} -g -O2 -Wall ${INCLUDEFLAGS}
endif
ifeq ($(COVERAGE),1)
CFLAGS += -DCOVERAGE_ENABLED
CFLAGS += -fprofile-arcs -ftest-coverage
ifneq ($(CFG),debug)
$(error You are not supposed to use coverage in release builds - read about it e.g. inlining issues, etc)
endif
endif
# Should we generate native FPU instructions for the SRC or not?
ifeq ($(FPU),0)
CFLAGS += -msoft-float
......@@ -117,8 +134,8 @@ else
@$(CC) -g -o $@ $^ ${LDFLAGS}
endif
ifeq ($(CFG),release)
@${CROSS_PREFIX}-objcopy --only-keep-debug $@ ${@}.debug
@${CROSS_PREFIX}-strip $@
@${RTEMS}/bin/${CROSS_PREFIX}-objcopy --only-keep-debug $@ ${@}.debug
@${RTEMS}/bin/${CROSS_PREFIX}-strip $@
endif
@echo Built with RTEMS at ${RTEMS_LIB} for ${LEON}.
......@@ -141,6 +158,23 @@ deps.$(SUFFIX)/%.d: %.c
clean:
@rm -rf deps.* objs.* bin.*
coverage:
# Stuff to add in and automate:
#
# Spawning my custom-compiled Leon3 QEMU simulator:
#
# ~/tool-src/misc/qemu-Leon3/qemu-system-sparc -no-reboot \
# -nographic -M leon3_generic -m 64M -kernel \
# bin.debug.FPU.leon3/fputest -gdb tcp::9976 -S
#
# Spawning GDB:
#
# sparc-rtems4.11-gdb -x contrib/coverage.gdb
#
# Gathering the now local .gcda files and creating a nice report:
# lcov --capture --directory .. --output-file coverage.info
# genhtml coverage.info --output-directory coverage
# Unless "make clean" is called, include the dependency files
# which are auto-generated. Don't fail if they are missing
# (-include), since they will be missing in the first invocation!
......
# Leon3 - via 127.0.0.1:1235
#
# file bin.debug.FPU.leon3.WITH_COVERAGE/fputest
# tar extended-remote 127.0.0.1:1235
# load bin.debug.FPU.leon3.WITH_COVERAGE/fputest
# Leon2
file bin.debug.FPU.leon2.WITH_COVERAGE/fputest
tar extended-remote me:1234
load bin.debug.FPU.leon2.WITH_COVERAGE/fputest
# The coverage exporting to the host
b base.c:79
commands 1
silent
set $filename = tmp->info->filename
set $dataBegin = buffer
set $dataEnd = buffer + bytesNeeded
eval "dump binary memory %s 0x%lx 0x%lx", $filename, $dataBegin, $dataEnd
echo dump binary memory $filename $dataBegin $dataEnd
echo \n
c
end
c
quit
/*
* This code is based on the GCOV-related code of the Linux kernel (kept under
* "kernel/gcov"). It basically uses the convert_to_gcda function to generate
* the .gcda files information upon application completion, and dump it on the
* host filesystem via GDB scripting.
*
* Original Linux banner follows below - but note that the Linux guys have
* nothing to do with these modifications, so blame me (and contact me)
* if something goes wrong.
*
* Thanassis Tsiodras
* Real-time Embedded Software Engineer
* System, Software and Technology Department
* European Space Agency
*
* e-mail: ttsiodras@gmail.com / Thanassis.Tsiodras@esa.int (work)
*
*/
/*
* This code maintains a list of active profiling data structures.
*
* Copyright IBM Corp. 2009
* Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
*
* Uses gcc-internal data definitions.
* Based on the gcov-kernel patch by:
* Hubertus Franke <frankeh@us.ibm.com>
* Nigel Hinds <nhinds@us.ibm.com>
* Rajan Ravindran <rajancr@us.ibm.com>
* Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
* Paul Larson
*/
#include "gcov_public.h"
#include "gcov.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct tagGcovInfo {
struct gcov_info *info;
struct tagGcovInfo *next;
} GcovInfo;
GcovInfo *headGcov = NULL;
/*
* __gcov_init is called by gcc-generated constructor code for each object
* file compiled with -fprofile-arcs.
*/
void __gcov_init(struct gcov_info *info)
{
printf(
"__gcov_init called for %s!\n",
gcov_info_filename(info));
fflush(stdout);
GcovInfo *newHead = malloc(sizeof(GcovInfo));
if (!newHead) {
puts("Out of memory!");
exit(1);
}
newHead->info = info;
newHead->next = headGcov;
headGcov = newHead;
}
void __gcov_exit()
{
GcovInfo *tmp = headGcov;
while(tmp) {
char *buffer;
unsigned bytesNeeded = convert_to_gcda(NULL, tmp->info);
buffer = malloc(bytesNeeded);
if (!buffer) {
puts("Out of memory!");
exit(1);
}
convert_to_gcda(buffer, tmp->info);
printf("Emitting %6d bytes for %s\n", bytesNeeded, gcov_info_filename(tmp->info));
free(buffer);
tmp = tmp->next;
}
}
void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
{
puts("__gcov_merge_add isn't called, right? Right? RIGHT?");
fflush(stdout);
exit(1);
}
/*
* This code provides functions to handle gcc's profiling data format
* introduced with gcc 4.7.
*
* This file is based heavily on gcc_3_4.c file.
*
* For a better understanding, refer to gcc source:
* gcc/gcov-io.h
* libgcc/libgcov.c
*
* Uses gcc-internal data definitions.
*/
#include "gcov.h"
#include <stdlib.h>
#include <memory.h>
#if __GNUC__ == 4 && __GNUC_MINOR__ >= 9
#define GCOV_COUNTERS 9
#else
#define GCOV_COUNTERS 8
#endif
#define GCOV_TAG_FUNCTION_LENGTH 3
typedef unsigned int u32;
typedef unsigned long long u64;
#define EINVAL 22
/**
* struct gcov_ctr_info - information about counters for a single function
* @num: number of counter values for this type
* @values: array of counter values for this type
*
* This data is generated by gcc during compilation and doesn't change
* at run-time with the exception of the values array.
*/
struct gcov_ctr_info {
unsigned int num;
gcov_type *values;
};
/**
* struct gcov_fn_info - profiling meta data per function
* @key: comdat key
* @ident: unique ident of function
* @lineno_checksum: function lineo_checksum
* @cfg_checksum: function cfg checksum
* @ctrs: instrumented counters
*
* This data is generated by gcc during compilation and doesn't change
* at run-time.
*
* Information about a single function. This uses the trailing array
* idiom. The number of counters is determined from the merge pointer
* array in gcov_info. The key is used to detect which of a set of
* comdat functions was selected -- it points to the gcov_info object
* of the object file containing the selected comdat function.
*/
struct gcov_fn_info {
const struct gcov_info *key;
unsigned int ident;
unsigned int lineno_checksum;
unsigned int cfg_checksum;
struct gcov_ctr_info ctrs[0];
};
/**
* struct gcov_info - profiling data per object file
* @version: gcov version magic indicating the gcc version used for compilation
* @next: list head for a singly-linked list
* @stamp: uniquifying time stamp
* @filename: name of the associated gcov data file
* @merge: merge functions (null for unused counter type)
* @n_functions: number of instrumented functions
* @functions: pointer to pointers to function information
*
* This data is generated by gcc during compilation and doesn't change
* at run-time with the exception of the next pointer.
*/
struct gcov_info {
unsigned int version;
struct gcov_info *next;
unsigned int stamp;
const char *filename;
void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
unsigned int n_functions;
struct gcov_fn_info **functions;
};
/*
* Determine whether a counter is active. Doesn't change at run-time.
*/
static int counter_active(struct gcov_info *info, unsigned int type)
{
return info->merge[type] ? 1 : 0;
}
/**
* gcov_info_filename - return info filename
* @info: profiling data set
*/
const char *gcov_info_filename(struct gcov_info *info)
{
return info->filename;
}
/**
* store_gcov_u32 - store 32 bit number in gcov format to buffer
* @buffer: target buffer or NULL
* @off: offset into the buffer
* @v: value to be stored
*
* Number format defined by gcc: numbers are recorded in the 32 bit
* unsigned binary form of the endianness of the machine generating the
* file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
* store anything.
*/
static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
{
u32 *data;
if (buffer) {
data = buffer + off;
*data = v;
}
return sizeof(*data);
}
/**
* store_gcov_u64 - store 64 bit number in gcov format to buffer
* @buffer: target buffer or NULL
* @off: offset into the buffer
* @v: value to be stored
*
* Number format defined by gcc: numbers are recorded in the 32 bit
* unsigned binary form of the endianness of the machine generating the
* file. 64 bit numbers are stored as two 32 bit numbers, the low part
* first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
* anything.
*/
static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
{
u32 *data;
if (buffer) {
data = buffer + off;
data[0] = (v & 0xffffffffUL);
data[1] = (v >> 32);
}
return sizeof(*data) * 2;
}
/**
* convert_to_gcda - convert profiling data set to gcda file format
* @buffer: the buffer to store file data or %NULL if no data should be stored
* @info: profiling data set to be converted
*
* Returns the number of bytes that were/would have been stored into the buffer.
*/
size_t convert_to_gcda(char *buffer, struct gcov_info *info)
{
struct gcov_fn_info *fi_ptr;
struct gcov_ctr_info *ci_ptr;
unsigned int fi_idx;
unsigned int ct_idx;
unsigned int cv_idx;
size_t pos = 0;
/* File header. */
pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
pos += store_gcov_u32(buffer, pos, info->version);
pos += store_gcov_u32(buffer, pos, info->stamp);
for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
fi_ptr = info->functions[fi_idx];
/* Function record. */
pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
ci_ptr = fi_ptr->ctrs;
for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
if (!counter_active(info, ct_idx))
continue;
/* Counter record. */
pos += store_gcov_u32(buffer, pos,
GCOV_TAG_FOR_COUNTER(ct_idx));
pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
pos += store_gcov_u64(buffer, pos,
ci_ptr->values[cv_idx]);
}
ci_ptr++;
}
}
return pos;
}
/*
* This code is based on the GCOV-related code of the Linux kernel (kept under
* "kernel/gcov"). It basically uses the convert_to_gcda function to generate
* the .gcda files information upon application completion, and dump it on the
* host filesystem via GDB scripting.
*
* Original Linux banner follows below - but note that the Linux guys have
* nothing to do with these modifications, so blame me (and contact me)
* if something goes wrong.
*
* Thanassis Tsiodras
* Real-time Embedded Software Engineer
* System, Software and Technology Department
* European Space Agency
*
* e-mail: ttsiodras@gmail.com / Thanassis.Tsiodras@esa.int (work)
*
*/
/*
* Profiling infrastructure declarations.
*
* This file is based on gcc-internal definitions. Data structures are
* defined to be compatible with gcc counterparts. For a better
* understanding, refer to gcc source: gcc/gcov-io.h.
*
* Copyright IBM Corp. 2009
* Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
*
* Uses gcc-internal data definitions.
*/
#ifndef GCOV_H
#define GCOV_H GCOV_H
#include <stdio.h>
#include "gcov_public.h"
/*
* Profiling data types used for gcc 3.4 and above - these are defined by
* gcc and need to be kept as close to the original definition as possible to
* remain compatible.
*/
#define GCOV_DATA_MAGIC ((unsigned int) 0x67636461)
#define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000)
#define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000)
#define GCOV_TAG_FOR_COUNTER(count) \
(GCOV_TAG_COUNTER_BASE + ((unsigned int) (count) << 17))
/* Opaque gcov_info. The gcov structures can change as for example in gcc 4.7 so
* we cannot use full definition here and they need to be placed in gcc specific
* implementation of gcov. This also means no direct access to the members in
* generic code and usage of the interface below.*/
struct gcov_info;
/* Interface to access gcov_info data */
const char *gcov_info_filename(struct gcov_info *info);
unsigned int gcov_info_version(struct gcov_info *info);
struct gcov_info *gcov_info_next(struct gcov_info *info);
void gcov_info_link(struct gcov_info *info);
void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info);
/* Base interface. */
enum gcov_action {
GCOV_ADD,
GCOV_REMOVE,
};
void gcov_event(enum gcov_action action, struct gcov_info *info);
void gcov_enable_events(void);
/* Iterator control. */
struct seq_file;
struct gcov_iterator;
struct gcov_iterator *gcov_iter_new(struct gcov_info *info);
void gcov_iter_free(struct gcov_iterator *iter);
void gcov_iter_start(struct gcov_iterator *iter);
int gcov_iter_next(struct gcov_iterator *iter);
int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq);
struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter);
/* gcov_info control. */
void gcov_info_reset(struct gcov_info *info);
int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2);
void gcov_info_add(struct gcov_info *dest, struct gcov_info *source);
void gcov_info_free(struct gcov_info *info);
struct gcov_link {
enum {
OBJ_TREE,
SRC_TREE,
} dir;
const char *ext;
};
extern const struct gcov_link gcov_link[];
#endif /* GCOV_H */
#ifndef __GCOV_PUBLIC_H__
#define __GCOV_PUBLIC_H__
#ifdef COVERAGE_ENABLED
struct gcov_info;
typedef long long gcov_type;
void __gcov_init(struct gcov_info *info);
void __gcov_exit(void);
void __gcov_merge_add(gcov_type *counters, unsigned int n_counters);
unsigned int convert_to_gcda(char *buffer, struct gcov_info *info);
#endif
#endif
/*
* Example initialization file - spawns 2 native FPU tasks
*
* Example initialization file - spawns 4 native tasks
* (2 stressing the FPU and 2 stressing the integer unit)
*/
#define CONFIGURE_INIT
#define TASKS 4
......@@ -8,6 +8,10 @@
#define DEFINE_VARS
#include "system.h"
#ifdef COVERAGE_ENABLED
#include "gcov_public.h"
#endif
#include <stdio.h>
#include <stdlib.h>
......@@ -66,5 +70,8 @@ rtems_task Init(rtems_task_argument argument)
printf("[PARENT] All tasks completed.\n");
fflush(stdout);
}
#ifdef COVERAGE_ENABLED
__gcov_exit();
#endif
exit(0);
}
......@@ -28,7 +28,6 @@ void memcheck()
}
space -= 1024*1024;
printf("\n[MEMCHECK] Memory available: %dK\n", space/1024);
p = malloc(space);
if (!p) {
puts("[MEMCHECK] Unexpected heap error. Aborting...");
......
#ifndef __SYSTEM_H__
#define __SYSTEM_H__
#include <rtems/score/types.h>
#include <rtems/rtems/types.h>
#include <rtems/rtems/tasks.h>
......@@ -26,3 +29,5 @@ void memcheck(void);
GLOBAL rtems_id g_init_task_id;
#include <rtems/confdefs.h>
#endif