Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/gcov/llvm.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Generic functionality for handling accesses to the PCI header from the
3
 * configuration space.
4
 *
5
 * Copyright (C) 2017 Citrix Systems R&D
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms and conditions of the GNU General Public
9
 * License, version 2, as published by the Free Software Foundation.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public
17
 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
//#include <errno.h>
21
//#include <inttypes.h>
22
23
//#include <string.h>
24
#include <xen/errno.h>
25
#include <xen/guest_access.h>
26
#include <xen/types.h>
27
28
#include <public/sysctl.h>
29
30
//#include "InstrProfData.inc"
31
32
enum llvm_profile_kind
33
{
34
  indirect_call,
35
  memop_size,
36
  num_kinds,
37
};
38
39
struct llvm_function_header {
40
  /*
41
   * Total size in bytes including this field. It must be a multiple
42
   * of sizeof(uint64_t).
43
   */
44
  uint32_t size;
45
  /*
46
   *The number of value profile kinds that has value profile data.
47
   * In this implementation, a value profile kind is considered to
48
   * have profile data if the number of value profile sites for the
49
   * kind is not zero. More aggressively, the implementation can
50
   * choose to check the actual data value: if none of the value sites
51
   * has any profiled values, the kind can be skipped.
52
   */
53
  uint32_t nr_value_kinds;
54
};
55
56
struct llvm_profile_node
57
{
58
    struct llvm_profile_node_val {
59
        uint64_t value;
60
        uint64_t count;
61
    } val;
62
    struct llvm_profile_node *next;
63
};
64
65
struct llvm_profile_data
66
{
67
    uint64_t name_ref;
68
    uint64_t function_hash;
69
70
    void *counter;
71
    void *function;
72
    struct llvm_profile_node **values;
73
74
    uint32_t nr_counters;
75
    uint16_t nr_value_sites[num_kinds];
76
};
77
78
struct llvm_profile_header {
79
    uint64_t magic;
80
    uint64_t version;
81
    uint64_t data_size;
82
    uint64_t counters_size;
83
    uint64_t names_size;
84
    uint64_t counters_delta;
85
    uint64_t names_delta;
86
    uint64_t value_kind_last;
87
};
88
89
int __llvm_profile_runtime;
90
91
1
#define INSTR_PROF_RAW_MAGIC_64 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
92
1
       (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 |  \
93
1
        (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129
94
#define INSTR_PROF_RAW_MAGIC_32 (uint64_t)255 << 56 | (uint64_t)'l' << 48 | \
95
       (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | (uint64_t)'o' << 24 |  \
96
        (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
97
98
extern struct llvm_profile_data __start___llvm_prf_data;
99
extern struct llvm_profile_data __stop___llvm_prf_data;
100
extern uint64_t __start___llvm_prf_cnts;
101
extern uint64_t __stop___llvm_prf_cnts;
102
extern char __start___llvm_prf_names;
103
extern char __stop___llvm_prf_names;
104
105
static uint64_t *__llvm_profile_begin_counters(void)
106
2
{
107
2
  return &__start___llvm_prf_cnts;
108
2
}
109
110
static uint64_t *__llvm_profile_end_counters(void)
111
2
{
112
2
  return &__stop___llvm_prf_cnts;
113
2
}
114
115
static const struct llvm_profile_data * __llvm_profile_begin_data(void)
116
2
{
117
2
  return &__start___llvm_prf_data;
118
2
}
119
120
static const struct llvm_profile_data * __llvm_profile_end_data(void)
121
2
{
122
2
  return &__stop___llvm_prf_data;
123
2
}
124
125
static const char *__llvm_profile_begin_names(void)
126
2
{
127
2
  return &__start___llvm_prf_names;
128
2
}
129
static const char *__llvm_profile_end_names(void)
130
2
{
131
2
  return &__stop___llvm_prf_names;
132
2
}
133
uint64_t __llvm_profile_get_data_size(const struct llvm_profile_data *Begin,
134
                                      const struct llvm_profile_data *End)
135
2
{
136
2
  uint64_t BeginI = (uint64_t)Begin, EndI = (uint64_t)End;
137
2
138
2
  return ((EndI + sizeof(struct llvm_profile_data) - 1) - BeginI) /
139
2
         sizeof(struct llvm_profile_data);
140
2
}
141
142
uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes)
143
2
{
144
2
  return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
145
2
}
146
147
void llvm_profile_reset_counters(void)
148
0
{
149
0
    const struct llvm_profile_data *data;
150
0
151
0
    memset(__llvm_profile_begin_counters(), 0,
152
0
           sizeof(uint64_t) * (__llvm_profile_end_counters() -
153
0
                               __llvm_profile_begin_counters()));
154
0
155
0
    for ( data = __llvm_profile_begin_data();
156
0
          data < __llvm_profile_end_data();
157
0
          data++ )
158
0
    {
159
0
        uint64_t site_count = 0;
160
0
        struct llvm_profile_node **nodes;
161
0
        uint32_t VKI, i;
162
0
163
0
        if ( !data->values )
164
0
          continue;
165
0
166
0
        nodes = data->values;
167
0
168
0
        for (VKI = 0; VKI <= num_kinds; VKI++)
169
0
            site_count += data->nr_value_sites[VKI];
170
0
171
0
        printk(XENLOG_INFO "site_count = %lu\n", site_count);
172
0
        for (i = 0; i < site_count; i++)
173
0
        {
174
0
            struct llvm_profile_node *node = nodes[i];
175
0
176
0
            while (node)
177
0
            {
178
0
                node->val.count = 0;
179
0
                node = node->next;
180
0
            }
181
0
        }
182
0
    }
183
0
}
184
185
void llvm_profile_write(XEN_GUEST_HANDLE_PARAM(char) buffer)
186
1
{
187
1
    const struct llvm_profile_data *DataBegin = __llvm_profile_begin_data();
188
1
    const struct llvm_profile_data *DataEnd = __llvm_profile_end_data();
189
1
    const uint64_t *CountersBegin = __llvm_profile_begin_counters();
190
1
    const uint64_t *CountersEnd = __llvm_profile_end_counters();
191
1
    const char *NamesBegin = __llvm_profile_begin_names();
192
1
    const char *NamesEnd = __llvm_profile_end_names();
193
1
    const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
194
1
    const uint64_t CountersSize = CountersEnd - CountersBegin;
195
1
    const uint64_t NamesSize = NamesEnd - NamesBegin;
196
1
    const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
197
1
    struct llvm_profile_header header;
198
1
    unsigned int off = 0;
199
1
200
1
#if BITS_PER_LONG == 64
201
1
    header.magic = INSTR_PROF_RAW_MAGIC_64;
202
1
#else
203
    header.magic = INSTR_PROF_RAW_MAGIC_32;
204
#endif
205
1
    /* XXX: hardcoded version number... */
206
1
    header.version = 4;
207
1
    header.data_size = DataSize;
208
1
    header.counters_size = CountersSize;
209
1
    header.names_size = NamesSize;
210
1
    header.counters_delta = (uintptr_t)CountersBegin;
211
1
    header.names_delta = (uintptr_t)NamesBegin;
212
1
    header.value_kind_last = num_kinds - 1;
213
1
214
1
    /* Copy data into the buffer. */
215
1
    copy_to_guest_offset(buffer, off, (char *)&header, sizeof(struct llvm_profile_header));
216
1
    off += sizeof(struct llvm_profile_header);
217
1
    copy_to_guest_offset(buffer, off, (char *)DataBegin, DataSize * sizeof(struct llvm_profile_data));
218
1
    off += DataSize * sizeof(struct llvm_profile_data);
219
1
    copy_to_guest_offset(buffer, off, (char *)CountersBegin, CountersSize * sizeof(uint64_t));
220
1
    off += CountersSize * sizeof(uint64_t);
221
1
    copy_to_guest_offset(buffer, off, NamesBegin, NamesSize * sizeof(uint8_t));
222
1
    off += NamesSize * sizeof(uint8_t);
223
1
    clear_guest_offset(buffer, off, Padding * sizeof(uint8_t));
224
1
    off += Padding * sizeof(uint8_t);
225
1
}
226
227
size_t llvm_profile_get_size(void)
228
1
{
229
1
    //const struct llvm_profile_data *data;
230
1
    const struct llvm_profile_data *DataBegin = __llvm_profile_begin_data();
231
1
    const struct llvm_profile_data *DataEnd = __llvm_profile_end_data();
232
1
    const uint64_t *CountersBegin = __llvm_profile_begin_counters();
233
1
    const uint64_t *CountersEnd = __llvm_profile_end_counters();
234
1
    const char *NamesBegin = __llvm_profile_begin_names();
235
1
    const char *NamesEnd = __llvm_profile_end_names();
236
1
    const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
237
1
    const uint64_t CountersSize = CountersEnd - CountersBegin;
238
1
    const uint64_t NamesSize = NamesEnd - NamesBegin;
239
1
    const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
240
1
    //size_t size = 0;
241
1
    //
242
1
    printk(XENLOG_INFO "Data size: %lu\n", DataSize);
243
1
    printk(XENLOG_INFO "Name size: %lu\n", NamesSize);
244
1
    printk(XENLOG_INFO "Counter size: %lu\n", CountersSize);
245
1
    printk(XENLOG_INFO "Padding size: %u\n", Padding);
246
1
247
1
    return sizeof(struct llvm_profile_header) +
248
1
           sizeof(struct llvm_profile_data) * DataSize +
249
1
           sizeof(uint64_t) * CountersSize + sizeof(uint8_t) * NamesSize +
250
1
           sizeof(uint8_t) * Padding;
251
1
252
1
#if 0
253
    for ( data = __llvm_profile_begin_data();
254
          data < __llvm_profile_end_data();
255
          data++ )
256
    {
257
        enum llvm_profile_kind kind;
258
        uint64_t site_count = 0;
259
        struct llvm_profile_node **nodes;
260
        uint32_t VKI, i;
261
262
        for ( kind = 0; kind < num_kinds; kind++ )
263
        {
264
          if ( !data->nr_value_sites[kind] )
265
            continue;
266
          else
267
            printf("data not null!\n!");
268
#if 0
269
        if ( !data->values )
270
          continue;
271
272
        nodes = data->values;
273
274
        for (VKI = 0; VKI <= num_kinds; VKI++)
275
            site_count += data->nr_value_sites[VKI];
276
277
        size += site_count * sizeof(struct llvm_function_header);
278
        for (i = 0; i < site_count; i++)
279
        {
280
            struct llvm_profile_node *node = nodes[i];
281
282
            while (node)
283
            {
284
                size += sizeof(struct llvm_profile_node_val);
285
                node = node->next;
286
            }
287
        }
288
#endif
289
        }
290
    }
291
#endif
292
1
293
1
    //return size;
294
1
}
295
296
int sysctl_gcov_op(struct xen_sysctl_gcov_op *op)
297
2
{
298
2
    switch ( op->cmd )
299
2
    {
300
1
    case XEN_SYSCTL_GCOV_get_size:
301
1
        op->size = llvm_profile_get_size();
302
1
        break;
303
0
    case XEN_SYSCTL_GCOV_reset:
304
0
        llvm_profile_reset_counters();
305
0
        break;
306
1
    case XEN_SYSCTL_GCOV_read:
307
1
    {
308
1
        XEN_GUEST_HANDLE_PARAM(char) buf;
309
1
310
1
        buf = guest_handle_cast(op->buffer, char);
311
1
        llvm_profile_write(buf);
312
1
313
1
        break;
314
1
    }
315
0
    default:
316
0
        return -ENOSYS;
317
2
    }
318
2
319
1
    return 0;
320
2
}