1
/* Copyright 2015 IBM Corp.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
#define _DEFAULT_SOURCE
18
#include <ccan/short_types/short_types.h>
20
#include <sys/types.h>
27
#include <sys/types.h>
33
typedef u32 gcov_unsigned_int;
35
/* You will need to pass -DTARGET__GNUC__=blah when building */
36
#if TARGET__GNUC__ >= 6 || (TARGET__GNUC__ >= 5 && TARGET__GNUC_MINOR__ >= 1)
37
#define GCOV_COUNTERS 10
39
#if TARGET__GNUC__ >= 4 && TARGET__GNUC_MINOR__ >= 9
40
#define GCOV_COUNTERS 9
42
#define GCOV_COUNTERS 8
45
typedef u64 gcov_type;
49
gcov_unsigned_int version;
51
struct gcov_info *next;
52
gcov_unsigned_int stamp;
55
u64 merge[GCOV_COUNTERS];
56
unsigned int n_functions;
58
struct gcov_fn_info **functions;
61
struct gcov_ctr_info {
62
gcov_unsigned_int num;
65
}__attribute__((packed));
68
const struct gcov_info *key;
70
unsigned int lineno_checksum;
71
unsigned int cfg_checksum;
73
// struct gcov_ctr_info ctrs[0];
74
} __attribute__((packed));
77
/* We have a list of all gcov info set up at startup */
78
struct gcov_info *gcov_info_list;
80
#define SKIBOOT_OFFSET 0x30000000
82
/* Endian of the machine producing the gcda. Which mean BE.
83
* because skiboot is BE.
84
* If skiboot is ever LE, go have fun.
86
static size_t write_u32(int fd, u32 _v)
89
return write(fd, &v, sizeof(v));
92
static size_t write_u64(int fd, u64 v)
95
b[0] = htobe32(v & 0xffffffffUL);
96
b[1] = htobe32(v >> 32);
98
write(fd, &b[0], sizeof(u32));
99
write(fd, &b[1], sizeof(u32));
103
#define GCOV_DATA_MAGIC ((unsigned int) 0x67636461)
104
#define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000)
105
#define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000)
106
#define GCOV_TAG_FOR_COUNTER(count) \
107
(GCOV_TAG_COUNTER_BASE + ((unsigned int) (count) << 17))
109
// gcc 4.7/4.8 specific
110
#define GCOV_TAG_FUNCTION_LENGTH 3
112
size_t skiboot_dump_size = 0x240000;
114
static inline const char* SKIBOOT_ADDR(const char* addr, const void* p)
116
const char* r= (addr + (be64toh((const u64)p) - SKIBOOT_OFFSET));
117
assert(r < (addr + skiboot_dump_size));
121
static int counter_active(struct gcov_info *info, unsigned int type)
123
return info->merge[type] ? 1 : 0;
126
static void write_gcda(char *addr, struct gcov_info* gi)
128
const char* filename = SKIBOOT_ADDR(addr, gi->filename);
131
struct gcov_fn_info *fn_info;
132
struct gcov_fn_info **functions;
133
struct gcov_ctr_info *ctr_info;
137
printf("Writing %s\n", filename);
139
fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
141
fprintf(stderr, "Error opening file %s: %d %s\n",
142
filename, errno, strerror(errno));
145
write_u32(fd, GCOV_DATA_MAGIC);
146
write_u32(fd, be32toh(gi->version));
147
write_u32(fd, be32toh(gi->stamp));
149
printf("version: %x\tstamp: %d\n", be32toh(gi->version), be32toh(gi->stamp));
150
printf("nfunctions: %d \n", be32toh(gi->n_functions));
152
for(fn = 0; fn < be32toh(gi->n_functions); fn++) {
153
functions = (struct gcov_fn_info**)
154
SKIBOOT_ADDR(addr, gi->functions);
156
fn_info = (struct gcov_fn_info*)
157
SKIBOOT_ADDR(addr, functions[fn]);
159
printf("function: %p\n", (void*)be64toh((u64)functions[fn]));
161
write_u32(fd, GCOV_TAG_FUNCTION);
162
write_u32(fd, GCOV_TAG_FUNCTION_LENGTH);
163
write_u32(fd, be32toh(fn_info->ident));
164
write_u32(fd, be32toh(fn_info->lineno_checksum));
165
write_u32(fd, be32toh(fn_info->cfg_checksum));
167
ctr_info = (struct gcov_ctr_info*)
168
((char*)fn_info + sizeof(struct gcov_fn_info));
170
for(ctr = 0; ctr < GCOV_COUNTERS; ctr++) {
171
if (!counter_active(gi, ctr))
174
write_u32(fd, (GCOV_TAG_FOR_COUNTER(ctr)));
175
write_u32(fd, be32toh(ctr_info->num)*2);
176
printf(" ctr %d gcov_ctr_info->num %u\n",
177
ctr, be32toh(ctr_info->num));
179
for(cv = 0; cv < be32toh(ctr_info->num); cv++) {
180
gcov_type *ctrv = (gcov_type *)
181
SKIBOOT_ADDR(addr, ctr_info->values);
182
//printf("%lx\n", be64toh(ctrv[cv]));
183
write_u64(fd, be64toh(ctrv[cv]));
193
int main(int argc, char *argv[])
201
printf("sizes: %zu %zu %zu %zu\n",
202
sizeof(gcov_unsigned_int),
203
sizeof(struct gcov_ctr_info),
204
sizeof(struct gcov_fn_info),
205
sizeof(struct gcov_info));
206
printf("TARGET GNUC: %d.%d\n", TARGET__GNUC__, TARGET__GNUC_MINOR__);
207
printf("GCOV_COUNTERS: %d\n", GCOV_COUNTERS);
210
fprintf(stderr, "Usage:\n"
211
"\t%s skiboot.dump gcov_offset\n\n",
216
/* argv[1] = skiboot.dump */
217
fd = open(argv[1], O_RDONLY);
219
fprintf(stderr, "Cannot open dump: %s (error %d %s)\n",
220
argv[1], errno, strerror(errno));
226
fprintf(stderr, "Cannot stat dump, %d %s\n",
227
errno, strerror(errno));
231
addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
232
assert(addr != NULL);
233
skiboot_dump_size = sb.st_size;
235
printf("Skiboot memory dump %p - %p\n",
236
(void*)SKIBOOT_OFFSET, (void*)SKIBOOT_OFFSET+sb.st_size);
238
gcov_list_addr = strtoll(argv[2], NULL, 0);
239
gcov_list_addr = (u64)(addr + (gcov_list_addr - SKIBOOT_OFFSET));
240
gcov_list_addr = be64toh(*(u64*)gcov_list_addr);
242
printf("Skiboot gcov_info_list at %p\n", (void*)gcov_list_addr);
245
gcov_info_list = (struct gcov_info *)(addr + (gcov_list_addr - SKIBOOT_OFFSET));
246
write_gcda(addr, gcov_info_list);
247
gcov_list_addr = be64toh((u64)gcov_info_list->next);
249
} while(gcov_list_addr);
251
munmap(addr, sb.st_size);