diff --git a/subsys/testsuite/Kconfig b/subsys/testsuite/Kconfig index e2e7fba764e..eff533a9da2 100644 --- a/subsys/testsuite/Kconfig +++ b/subsys/testsuite/Kconfig @@ -78,7 +78,8 @@ config COVERAGE_GCOV_HEAP_SIZE default 16384 help This option configures the heap size allocated for gcov coverage - data to be dumped over serial. + data to be dumped over serial. If the value is 0, no buffer will be used, + data will be dumped directly over serial. config COVERAGE_DUMP bool "Dump coverage data on exit" @@ -86,6 +87,15 @@ config COVERAGE_DUMP help Dump collected coverage information to console on exit. +config FORCE_COVERAGE + bool "Force coverage" + select HAS_COVERAGE_SUPPORT + help + Regardless of platform support, it will enable coverage data production. + If the platform does not support coverage by default, setting this config + does not guarantee that coverage data will be gathered. + Application may not fit memory or crash at runtime. + config TEST_USERSPACE bool "Indicate that this test exercises user mode" help diff --git a/subsys/testsuite/coverage/coverage.c b/subsys/testsuite/coverage/coverage.c index e787135ffdc..dc120c14605 100644 --- a/subsys/testsuite/coverage/coverage.c +++ b/subsys/testsuite/coverage/coverage.c @@ -36,25 +36,54 @@ void __gcov_exit(void) } /** - * buff_write_u64 - Store 64 bit data on a buffer and return the size + * print_u8 - Print 8 bit of gcov data + */ +static inline void print_u8(uint8_t v) +{ + printk("%02x", v); +} + +/** + * print_u32 - Print 32 bit of gcov data + */ +static inline void print_u32(uint32_t v) +{ + uint8_t *ptr = (uint8_t *)&v; + + print_u8(*ptr); + print_u8(*(ptr+1)); + print_u8(*(ptr+2)); + print_u8(*(ptr+3)); +} + +/** + * write_u64 - Store 64 bit data on a buffer and return the size */ -static inline void buff_write_u64(void *buffer, size_t *off, uint64_t v) +static inline void write_u64(void *buffer, size_t *off, uint64_t v) { - memcpy((uint8_t *)buffer + *off, (uint8_t *)&v, sizeof(v)); + if (buffer != NULL) { + memcpy((uint8_t *)buffer + *off, (uint8_t *)&v, sizeof(v)); + } else { + print_u32(*((uint32_t *)&v)); + print_u32(*(((uint32_t *)&v) + 1)); + } *off = *off + sizeof(uint64_t); } /** - * buff_write_u32 - Store 32 bit data on a buffer and return the size + * write_u32 - Store 32 bit data on a buffer and return the size */ -static inline void buff_write_u32(void *buffer, size_t *off, uint32_t v) +static inline void write_u32(void *buffer, size_t *off, uint32_t v) { - memcpy((uint8_t *)buffer + *off, (uint8_t *)&v, sizeof(v)); + if (buffer != NULL) { + memcpy((uint8_t *)buffer + *off, (uint8_t *)&v, sizeof(v)); + } else { + print_u32(v); + } *off = *off + sizeof(uint32_t); } - size_t calculate_buff_size(struct gcov_info *info) { uint32_t iter; @@ -102,14 +131,13 @@ size_t calculate_buff_size(struct gcov_info *info) return size; } - /** - * populate_buffer - convert from gcov data set (info) to + * gcov_to_gcda - convert from gcov data set (info) to * .gcda file format. * This buffer will now have info similar to a regular gcda * format. */ -size_t populate_buffer(uint8_t *buffer, struct gcov_info *info) +size_t gcov_to_gcda(uint8_t *buffer, struct gcov_info *info) { struct gcov_fn_info *functions; struct gcov_ctr_info *counters_per_func; @@ -119,22 +147,22 @@ size_t populate_buffer(uint8_t *buffer, struct gcov_info *info) size_t buffer_write_position = 0; /* File header. */ - buff_write_u32(buffer, - &buffer_write_position, - GCOV_DATA_MAGIC); + write_u32(buffer, + &buffer_write_position, + GCOV_DATA_MAGIC); - buff_write_u32(buffer, - &buffer_write_position, - info->version); + write_u32(buffer, + &buffer_write_position, + info->version); - buff_write_u32(buffer, - &buffer_write_position, - info->stamp); + write_u32(buffer, + &buffer_write_position, + info->stamp); #ifdef GCOV_12_FORMAT - buff_write_u32(buffer, - &buffer_write_position, - info->checksum); + write_u32(buffer, + &buffer_write_position, + info->checksum); #endif for (iter_functions = 0U; @@ -144,25 +172,25 @@ size_t populate_buffer(uint8_t *buffer, struct gcov_info *info) functions = info->functions[iter_functions]; - buff_write_u32(buffer, - &buffer_write_position, - GCOV_TAG_FUNCTION); + write_u32(buffer, + &buffer_write_position, + GCOV_TAG_FUNCTION); - buff_write_u32(buffer, - &buffer_write_position, - GCOV_TAG_FUNCTION_LENGTH); + write_u32(buffer, + &buffer_write_position, + GCOV_TAG_FUNCTION_LENGTH); - buff_write_u32(buffer, - &buffer_write_position, - functions->ident); + write_u32(buffer, + &buffer_write_position, + functions->ident); - buff_write_u32(buffer, - &buffer_write_position, - functions->lineno_checksum); + write_u32(buffer, + &buffer_write_position, + functions->lineno_checksum); - buff_write_u32(buffer, - &buffer_write_position, - functions->cfg_checksum); + write_u32(buffer, + &buffer_write_position, + functions->cfg_checksum); counters_per_func = functions->ctrs; @@ -174,29 +202,28 @@ size_t populate_buffer(uint8_t *buffer, struct gcov_info *info) continue; } - buff_write_u32(buffer, - &buffer_write_position, - GCOV_TAG_FOR_COUNTER(iter_counts)); + write_u32(buffer, + &buffer_write_position, + GCOV_TAG_FOR_COUNTER(iter_counts)); #ifdef GCOV_12_FORMAT /* GCOV 12 counts the length by bytes */ - buff_write_u32(buffer, - &buffer_write_position, - counters_per_func->num * 2U * 4); + write_u32(buffer, + &buffer_write_position, + counters_per_func->num * 2U * 4); #else - buff_write_u32(buffer, - &buffer_write_position, - counters_per_func->num * 2U); + write_u32(buffer, + &buffer_write_position, + counters_per_func->num * 2U); #endif for (iter_counter_values = 0U; iter_counter_values < counters_per_func->num; iter_counter_values++) { - buff_write_u64(buffer, - &buffer_write_position, - counters_per_func->\ - values[iter_counter_values]); + write_u64(buffer, + &buffer_write_position, + counters_per_func->values[iter_counter_values]); } counters_per_func++; @@ -205,20 +232,21 @@ size_t populate_buffer(uint8_t *buffer, struct gcov_info *info) return buffer_write_position; } -void dump_on_console(const char *filename, char *ptr, size_t len) +void dump_on_console_start(const char *filename) { - uint32_t iter; - printk("\n%c", FILE_START_INDICATOR); while (*filename != '\0') { printk("%c", *filename++); } printk("%c", GCOV_DUMP_SEPARATOR); +} - /* Data dump */ - - for (iter = 0U; iter < len; iter++) { - printk(" %02x", (uint8_t)*ptr++); +void dump_on_console_data(char *ptr, size_t len) +{ + if (ptr != NULL) { + for (size_t iter = 0U; iter < len; iter++) { + print_u8((uint8_t)*ptr++); + } } } @@ -237,21 +265,22 @@ void gcov_coverage_dump(void) printk("\nGCOV_COVERAGE_DUMP_START"); while (gcov_list) { + dump_on_console_start(gcov_list->filename); size = calculate_buff_size(gcov_list); buffer = k_heap_alloc(&gcov_heap, size, K_NO_WAIT); - if (!buffer) { + if (CONFIG_COVERAGE_GCOV_HEAP_SIZE > 0 && !buffer) { printk("No Mem available to continue dump\n"); goto coverage_dump_end; } - written_size = populate_buffer(buffer, gcov_list); + written_size = gcov_to_gcda(buffer, gcov_list); if (written_size != size) { printk("Write Error on buff\n"); goto coverage_dump_end; } - dump_on_console(gcov_list->filename, buffer, size); + dump_on_console_data(buffer, size); k_heap_free(&gcov_heap, buffer); gcov_list = gcov_list->next;