1 /*
2 * This code maintains a list of active profiling data structures.
3 *
4 * Copyright IBM Corp. 2009
5 * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
6 *
7 * Uses gcc-internal data definitions.
8 * Based on the gcov-kernel patch by:
9 * Hubertus Franke <frankeh@us.ibm.com>
10 * Nigel Hinds <nhinds@us.ibm.com>
11 * Rajan Ravindran <rajancr@us.ibm.com>
12 * Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
13 * Paul Larson
14 *
15 * Modified for Xen by:
16 * Wei Liu <wei.liu2@citrix.com>
17 */
18
19 #include <xen/errno.h>
20 #include <xen/guest_access.h>
21 #include <xen/types.h>
22
23 #include <public/sysctl.h>
24
25 #include "gcov.h"
26
27 /**
28 * gcov_store_uint32 - store 32 bit number in gcov format to buffer
29 * @buffer: target buffer or NULL
30 * @off: offset into the buffer
31 * @v: value to be stored
32 *
33 * Number format defined by gcc: numbers are recorded in the 32 bit
34 * unsigned binary form of the endianness of the machine generating the
35 * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
36 * store anything.
37 */
gcov_store_uint32(void * buffer,size_t off,uint32_t v)38 size_t gcov_store_uint32(void *buffer, size_t off, uint32_t v)
39 {
40 uint32_t *data;
41
42 if ( buffer )
43 {
44 data = buffer + off;
45 *data = v;
46 }
47
48 return sizeof(*data);
49 }
50
51 /**
52 * gcov_store_uint64 - store 64 bit number in gcov format to buffer
53 * @buffer: target buffer or NULL
54 * @off: offset into the buffer
55 * @v: value to be stored
56 *
57 * Number format defined by gcc: numbers are recorded in the 32 bit
58 * unsigned binary form of the endianness of the machine generating the
59 * file. 64 bit numbers are stored as two 32 bit numbers, the low part
60 * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
61 * anything.
62 */
gcov_store_uint64(void * buffer,size_t off,uint64_t v)63 size_t gcov_store_uint64(void *buffer, size_t off, uint64_t v)
64 {
65 uint32_t *data;
66
67 if ( buffer )
68 {
69 data = buffer + off;
70
71 data[0] = (v & 0xffffffffUL);
72 data[1] = (v >> 32);
73 }
74
75 return sizeof(*data) * 2;
76 }
77
gcov_info_payload_size(const struct gcov_info * info)78 static size_t gcov_info_payload_size(const struct gcov_info *info)
79 {
80 return gcov_info_to_gcda(NULL, info);
81 }
82
gcov_info_dump_payload(const struct gcov_info * info,XEN_GUEST_HANDLE_PARAM (char)buffer,uint32_t * off)83 static int gcov_info_dump_payload(const struct gcov_info *info,
84 XEN_GUEST_HANDLE_PARAM(char) buffer,
85 uint32_t *off)
86 {
87 char *buf;
88 uint32_t buf_size;
89 int ret;
90
91 /*
92 * Allocate a buffer and dump payload there. This helps us to not
93 * have copy_to_guest in other functions and retain their simple
94 * semantics.
95 */
96
97 buf_size = gcov_info_payload_size(info);
98 buf = xmalloc_array(char, buf_size);
99
100 if ( !buf )
101 {
102 ret = -ENOMEM;
103 goto out;
104 }
105
106 gcov_info_to_gcda(buf, info);
107
108 if ( copy_to_guest_offset(buffer, *off, buf, buf_size) )
109 {
110 ret = -EFAULT;
111 goto out;
112 }
113 *off += buf_size;
114
115 ret = 0;
116 out:
117 xfree(buf);
118 return ret;
119
120 }
121
gcov_get_size(void)122 static uint32_t gcov_get_size(void)
123 {
124 uint32_t total_size = sizeof(uint32_t); /* Magic number XCOV */
125 struct gcov_info *info = NULL;
126
127 while ( (info = gcov_info_next(info)) )
128 {
129 /* File name length, including trailing \0 */
130 total_size += strlen(gcov_info_filename(info)) + 1;
131
132 /* Payload size field */
133 total_size += sizeof(uint32_t);
134
135 /* Payload itself */
136 total_size += gcov_info_payload_size(info);
137 }
138
139 return total_size;
140 }
141
gcov_reset_all_counters(void)142 static void gcov_reset_all_counters(void)
143 {
144 struct gcov_info *info = NULL;
145
146 while ( (info = gcov_info_next(info)) )
147 gcov_info_reset(info);
148 }
149
gcov_dump_one_record(const struct gcov_info * info,XEN_GUEST_HANDLE_PARAM (char)buffer,uint32_t * off)150 static int gcov_dump_one_record(const struct gcov_info *info,
151 XEN_GUEST_HANDLE_PARAM(char) buffer,
152 uint32_t *off)
153 {
154 uint32_t payload_size;
155 uint32_t len;
156
157 /* File name, including trailing \0 */
158 len = strlen(gcov_info_filename(info)) + 1;
159 if ( copy_to_guest_offset(buffer, *off, gcov_info_filename(info), len) )
160 return -EFAULT;
161 *off += len;
162
163 payload_size = gcov_info_payload_size(info);
164 /* Payload size */
165 if ( copy_to_guest_offset(buffer, *off, (char*)&payload_size,
166 sizeof(uint32_t)) )
167 return -EFAULT;
168 *off += sizeof(uint32_t);
169
170 /* Payload itself */
171 return gcov_info_dump_payload(info, buffer, off);
172 }
173
gcov_dump_all(XEN_GUEST_HANDLE_PARAM (char)buffer,uint32_t * buffer_size)174 static int gcov_dump_all(XEN_GUEST_HANDLE_PARAM(char) buffer,
175 uint32_t *buffer_size)
176 {
177 uint32_t off;
178 uint32_t magic = XEN_GCOV_FORMAT_MAGIC;
179 struct gcov_info *info = NULL;
180 int ret;
181
182 if ( *buffer_size < gcov_get_size() )
183 {
184 ret = -ENOBUFS;
185 goto out;
186 }
187
188 off = 0;
189
190 /* Magic number */
191 if ( copy_to_guest_offset(buffer, off, (char *)&magic, sizeof(magic)) )
192 {
193 ret = -EFAULT;
194 goto out;
195 }
196 off += sizeof(magic);
197
198 while ( (info = gcov_info_next(info)) )
199 {
200 ret = gcov_dump_one_record(info, buffer, &off);
201 if ( ret )
202 goto out;
203 }
204
205 *buffer_size = off;
206
207 ret = 0;
208 out:
209 return ret;
210 }
211
sysctl_gcov_op(struct xen_sysctl_gcov_op * op)212 int sysctl_gcov_op(struct xen_sysctl_gcov_op *op)
213 {
214 int ret;
215
216 switch ( op->cmd )
217 {
218 case XEN_SYSCTL_GCOV_get_size:
219 op->size = gcov_get_size();
220 ret = 0;
221 break;
222
223 case XEN_SYSCTL_GCOV_read:
224 {
225 XEN_GUEST_HANDLE_PARAM(char) buf;
226 uint32_t size = op->size;
227
228 buf = guest_handle_cast(op->buffer, char);
229
230 ret = gcov_dump_all(buf, &size);
231 op->size = size;
232
233 break;
234 }
235
236 case XEN_SYSCTL_GCOV_reset:
237 gcov_reset_all_counters();
238 ret = 0;
239 break;
240
241 default:
242 ret = -EOPNOTSUPP;
243 break;
244 }
245
246 return ret;
247 }
248
249 /*
250 * Local variables:
251 * mode: C
252 * c-file-style: "BSD"
253 * c-basic-offset: 4
254 * tab-width: 4
255 * indent-tabs-mode: nil
256 * End:
257 */
258