Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2018 Intel Corporation
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : #include <zephyr.h>
8 : : #include <stdio.h>
9 : : #include <stdint.h>
10 : : #include <errno.h>
11 : : #include "coverage.h"
12 : :
13 : :
14 : : #if defined(CONFIG_X86) || defined(CONFIG_SOC_SERIES_MPS2)
15 : : #define MALLOC_MAX_HEAP_SIZE 32768
16 : : #define MALLOC_MIN_BLOCK_SIZE 128
17 : : #else
18 : : #define MALLOC_MAX_HEAP_SIZE 16384
19 : : #define MALLOC_MIN_BLOCK_SIZE 64
20 : : #endif
21 : :
22 : :
23 : : //K_HEAP_DEFINE(gcov_heap, MALLOC_MAX_HEAP_SIZE);
24 : : K_HEAP_DEFINE(gcov_heap, 32768);
25 : :
26 : : static struct gcov_info *gcov_info_head;
27 : :
28 : : /**
29 : : * Is called by gcc-generated constructor code for each object file compiled
30 : : * with -fprofile-arcs.
31 : : */
32 : 212 : void __gcov_init(struct gcov_info *info)
33 : : {
34 : 212 : info->next = gcov_info_head;
35 : 212 : gcov_info_head = info;
36 : 212 : }
37 : :
38 : 0 : void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
39 : : {
40 : : /* Unused. */
41 : 0 : }
42 : :
43 : 0 : void __gcov_exit(void)
44 : : {
45 : : /* Unused. */
46 : 0 : }
47 : :
48 : : /**
49 : : * buff_write_u64 - Store 64 bit data on a buffer and return the size
50 : : */
51 : :
52 : : #define MASK_32BIT (0xffffffffUL)
53 : 5995 : static inline void buff_write_u64(void *buffer, size_t *off, uint64_t v)
54 : : {
55 : 5995 : *((uint32_t *)((uint8_t *)buffer + *off) + 0) = (uint32_t)(v & MASK_32BIT);
56 : 5995 : *((uint32_t *)((uint8_t *)buffer + *off) + 1) = (uint32_t)((v >> 32) &
57 : : MASK_32BIT);
58 : 5995 : *off = *off + sizeof(uint64_t);
59 : 5995 : }
60 : :
61 : : /**
62 : : * buff_write_u32 - Store 32 bit data on a buffer and return the size
63 : : */
64 : 10690 : static inline void buff_write_u32(void *buffer, size_t *off, uint32_t v)
65 : : {
66 : 10690 : *((uint32_t *)((uint8_t *)buffer + *off)) = v;
67 : 10690 : *off = *off + sizeof(uint32_t);
68 : 10690 : }
69 : :
70 : :
71 : 68 : size_t calculate_buff_size(struct gcov_info *info)
72 : : {
73 : : uint32_t iter;
74 : : uint32_t iter_1;
75 : : uint32_t iter_2;
76 : : /* few Fixed values at the start version, stamp and magic number. */
77 : 68 : uint32_t size = sizeof(uint32_t) * 3;
78 : :
79 [ + + ]: 1570 : for (iter = 0U; iter < info->n_functions; iter++) {
80 : : /* space for TAG_FUNCTION and FUNCTION_LENGTH
81 : : * ident
82 : : * lineno_checksum
83 : : * cfg_checksum
84 : : */
85 : 1502 : size += (sizeof(uint32_t) * 5);
86 : :
87 [ + + ]: 13518 : for (iter_1 = 0U; iter_1 < GCOV_COUNTERS; iter_1++) {
88 [ + + ]: 12016 : if (!info->merge[iter_1]) {
89 : 10514 : continue;
90 : : }
91 : :
92 : : /* for function counter and number of values */
93 : 1502 : size += (sizeof(uint32_t) * 2);
94 : :
95 : 1502 : for (iter_2 = 0U;
96 [ + + ]: 7501 : iter_2 < info->functions[iter]->ctrs->num;
97 : 5999 : iter_2++) {
98 : :
99 : : /* Iter for values which is uint64_t */
100 : 5999 : size += (sizeof(uint64_t));
101 : : }
102 : :
103 : : }
104 : :
105 : :
106 : : }
107 : :
108 : 68 : return size;
109 : : }
110 : :
111 : :
112 : : /**
113 : : * populate_buffer - convert from gcov data set (info) to
114 : : * .gcda file format.
115 : : * This buffer will now have info similar to a regular gcda
116 : : * format.
117 : : */
118 : 68 : size_t populate_buffer(uint8_t *buffer, struct gcov_info *info)
119 : : {
120 : : struct gcov_fn_info *functions;
121 : : struct gcov_ctr_info *counters_per_func;
122 : : uint32_t iter_functions;
123 : : uint32_t iter_counts;
124 : : uint32_t iter_counter_values;
125 : 68 : size_t buffer_write_position = 0;
126 : :
127 : : /* File header. */
128 : 68 : buff_write_u32(buffer,
129 : : &buffer_write_position,
130 : : GCOV_DATA_MAGIC);
131 : :
132 : 68 : buff_write_u32(buffer,
133 : : &buffer_write_position,
134 : : info->version);
135 : :
136 : 68 : buff_write_u32(buffer,
137 : : &buffer_write_position,
138 : : info->stamp);
139 : :
140 : 68 : for (iter_functions = 0U;
141 [ + + ]: 1563 : iter_functions < info->n_functions;
142 : 1495 : iter_functions++) {
143 : :
144 : 1496 : functions = info->functions[iter_functions];
145 : :
146 : :
147 : 1496 : buff_write_u32(buffer,
148 : : &buffer_write_position,
149 : : GCOV_TAG_FUNCTION);
150 : :
151 : 1496 : buff_write_u32(buffer,
152 : : &buffer_write_position,
153 : : GCOV_TAG_FUNCTION_LENGTH);
154 : :
155 : 1496 : buff_write_u32(buffer,
156 : : &buffer_write_position,
157 : : functions->ident);
158 : :
159 : 1496 : buff_write_u32(buffer,
160 : : &buffer_write_position,
161 : : functions->lineno_checksum);
162 : :
163 : 1496 : buff_write_u32(buffer,
164 : : &buffer_write_position,
165 : : functions->cfg_checksum);
166 : :
167 : 1496 : counters_per_func = functions->ctrs;
168 : :
169 [ + + ]: 13456 : for (iter_counts = 0U;
170 : : iter_counts < GCOV_COUNTERS;
171 : 11960 : iter_counts++) {
172 : :
173 [ + + ]: 11961 : if (!info->merge[iter_counts]) {
174 : 10465 : continue;
175 : : }
176 : :
177 : 1496 : buff_write_u32(buffer,
178 : : &buffer_write_position,
179 : 1496 : GCOV_TAG_FOR_COUNTER(iter_counts));
180 : :
181 : 1496 : buff_write_u32(buffer,
182 : : &buffer_write_position,
183 : 1496 : counters_per_func->num * 2U);
184 : :
185 : 1497 : for (iter_counter_values = 0U;
186 [ + + ]: 7480 : iter_counter_values < counters_per_func->num;
187 : 5983 : iter_counter_values++) {
188 : :
189 : 5985 : buff_write_u64(buffer,
190 : : &buffer_write_position,
191 : 5985 : counters_per_func->\
192 : 5985 : values[iter_counter_values]);
193 : : }
194 : :
195 : 1495 : counters_per_func++;
196 : : }
197 : : }
198 : 67 : return buffer_write_position;
199 : : }
200 : :
201 : 67 : void dump_on_console(const char *filename, char *ptr, size_t len)
202 : : {
203 : : uint32_t iter;
204 : :
205 : 67 : printk("\n%c", FILE_START_INDICATOR);
206 [ + + ]: 11511 : while (*filename != '\0') {
207 : 11444 : printk("%c", *filename++);
208 : : }
209 : 67 : printk("%c", GCOV_DUMP_SEPARATOR);
210 : :
211 : : /* Data dump */
212 : :
213 [ + + ]: 90223 : for (iter = 0U; iter < len; iter++) {
214 : 90156 : printk(" %02x", (uint8_t)*ptr++);
215 : : }
216 : 67 : }
217 : :
218 : : /**
219 : : * Retrieves gcov coverage data and sends it over the given interface.
220 : : */
221 : 1 : void gcov_coverage_dump(void)
222 : : {
223 : : uint8_t *buffer;
224 : : size_t size;
225 : : size_t written_size;
226 : 1 : struct gcov_info *gcov_list_first = gcov_info_head;
227 : 1 : struct gcov_info *gcov_list = gcov_info_head;
228 : :
229 : 1 : k_sched_lock();
230 : 1 : printk("\nGCOV_COVERAGE_DUMP_START");
231 [ + - ]: 68 : while (gcov_list) {
232 : :
233 : 68 : size = calculate_buff_size(gcov_list);
234 : :
235 : 68 : buffer = k_heap_alloc(&gcov_heap, size, K_NO_WAIT);
236 [ - + ]: 68 : if (!buffer) {
237 : 0 : printk("No Mem available to continue dump\n");
238 : 0 : goto coverage_dump_end;
239 : : }
240 : :
241 : 68 : written_size = populate_buffer(buffer, gcov_list);
242 [ - + ]: 67 : if (written_size != size) {
243 : 0 : printk("Write Error on buff\n");
244 : 0 : goto coverage_dump_end;
245 : : }
246 : :
247 : 67 : dump_on_console(gcov_list->filename, buffer, size);
248 : :
249 : 67 : k_heap_free(&gcov_heap, buffer);
250 : 67 : gcov_list = gcov_list->next;
251 [ - + ]: 67 : if (gcov_list_first == gcov_list) {
252 : 0 : goto coverage_dump_end;
253 : : }
254 : : }
255 : 0 : coverage_dump_end:
256 : 0 : printk("\nGCOV_COVERAGE_DUMP_END\n");
257 : 0 : k_sched_unlock();
258 : 0 : return;
259 : : }
260 : :
261 : :
262 : : /* Initialize the gcov by calling the required constructors */
263 : 1 : void gcov_static_init(void)
264 : : {
265 : : extern uintptr_t __init_array_start, __init_array_end;
266 : 1 : uintptr_t func_pointer_start = (uintptr_t) &__init_array_start;
267 : 1 : uintptr_t func_pointer_end = (uintptr_t) &__init_array_end;
268 : :
269 [ + + ]: 107 : while (func_pointer_start < func_pointer_end) {
270 : : void (**p)(void);
271 : : /* get function pointer */
272 : 106 : p = (void (**)(void)) func_pointer_start;
273 : 106 : (*p)();
274 : 106 : func_pointer_start += sizeof(p);
275 : : }
276 : 1 : }
|