~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/extract-gcov.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2015 IBM Corp.
 
2
 *
 
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
 
6
 *
 
7
 *      http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
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
 
12
 * implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#define _DEFAULT_SOURCE
 
18
#include <ccan/short_types/short_types.h>
 
19
#include <endian.h>
 
20
#include <sys/types.h>
 
21
#include <sys/stat.h>
 
22
#include <fcntl.h>
 
23
#include <stdio.h>
 
24
#include <sys/mman.h>
 
25
#include <assert.h>
 
26
#include <stdlib.h>
 
27
#include <sys/types.h>
 
28
#include <sys/stat.h>
 
29
#include <unistd.h>
 
30
#include <errno.h>
 
31
#include <string.h>
 
32
 
 
33
typedef u32 gcov_unsigned_int;
 
34
 
 
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
 
38
#else
 
39
#if TARGET__GNUC__ >= 4 && TARGET__GNUC_MINOR__ >= 9
 
40
#define GCOV_COUNTERS                   9
 
41
#else
 
42
#define GCOV_COUNTERS                   8
 
43
#endif /* GCC 4.9 */
 
44
#endif /* GCC 5.1 */
 
45
typedef u64 gcov_type;
 
46
 
 
47
struct gcov_info
 
48
{
 
49
        gcov_unsigned_int version;
 
50
        u32 _padding;
 
51
        struct gcov_info *next;
 
52
        gcov_unsigned_int stamp;
 
53
        u32 _padding2;
 
54
        const char *filename;
 
55
        u64 merge[GCOV_COUNTERS];
 
56
        unsigned int n_functions;
 
57
        u32 _padding3;
 
58
        struct gcov_fn_info **functions;
 
59
};
 
60
 
 
61
struct gcov_ctr_info {
 
62
        gcov_unsigned_int num;
 
63
        u32 _padding;
 
64
        gcov_type *values;
 
65
}__attribute__((packed));
 
66
 
 
67
struct gcov_fn_info {
 
68
        const struct gcov_info *key;
 
69
        unsigned int ident;
 
70
        unsigned int lineno_checksum;
 
71
        unsigned int cfg_checksum;
 
72
        u32 _padding;
 
73
//        struct gcov_ctr_info ctrs[0];
 
74
} __attribute__((packed));
 
75
 
 
76
 
 
77
/* We have a list of all gcov info set up at startup */
 
78
struct gcov_info *gcov_info_list;
 
79
 
 
80
#define SKIBOOT_OFFSET 0x30000000
 
81
 
 
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.
 
85
 */
 
86
static size_t write_u32(int fd, u32 _v)
 
87
{
 
88
        u32 v = htobe32(_v);
 
89
        return write(fd, &v, sizeof(v));
 
90
}
 
91
 
 
92
static size_t write_u64(int fd, u64 v)
 
93
{
 
94
        u32 b[2];
 
95
        b[0] = htobe32(v & 0xffffffffUL);
 
96
        b[1] = htobe32(v >> 32);
 
97
 
 
98
        write(fd, &b[0], sizeof(u32));
 
99
        write(fd, &b[1], sizeof(u32));
 
100
        return sizeof(u64);
 
101
}
 
102
 
 
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))
 
108
 
 
109
// gcc 4.7/4.8 specific
 
110
#define GCOV_TAG_FUNCTION_LENGTH        3
 
111
 
 
112
size_t skiboot_dump_size = 0x240000;
 
113
 
 
114
static inline const char* SKIBOOT_ADDR(const char* addr, const void* p)
 
115
{
 
116
        const char* r= (addr + (be64toh((const u64)p) - SKIBOOT_OFFSET));
 
117
        assert(r < (addr + skiboot_dump_size));
 
118
        return r;
 
119
}
 
120
 
 
121
static int counter_active(struct gcov_info *info, unsigned int type)
 
122
{
 
123
        return info->merge[type] ? 1 : 0;
 
124
}
 
125
 
 
126
static void write_gcda(char *addr, struct gcov_info* gi)
 
127
{
 
128
        const char* filename = SKIBOOT_ADDR(addr, gi->filename);
 
129
        int fd;
 
130
        u32 fn;
 
131
        struct gcov_fn_info *fn_info;
 
132
        struct gcov_fn_info **functions;
 
133
        struct gcov_ctr_info *ctr_info;
 
134
        u32 ctr;
 
135
        u32 cv;
 
136
 
 
137
        printf("Writing %s\n", filename);
 
138
 
 
139
        fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
 
140
        if (fd < 0) {
 
141
                fprintf(stderr, "Error opening file %s: %d %s\n",
 
142
                        filename, errno, strerror(errno));
 
143
                exit(EXIT_FAILURE);
 
144
        }
 
145
        write_u32(fd, GCOV_DATA_MAGIC);
 
146
        write_u32(fd, be32toh(gi->version));
 
147
        write_u32(fd, be32toh(gi->stamp));
 
148
 
 
149
        printf("version: %x\tstamp: %d\n", be32toh(gi->version), be32toh(gi->stamp));
 
150
        printf("nfunctions: %d \n", be32toh(gi->n_functions));
 
151
 
 
152
        for(fn = 0; fn < be32toh(gi->n_functions); fn++) {
 
153
                functions = (struct gcov_fn_info**)
 
154
                        SKIBOOT_ADDR(addr, gi->functions);
 
155
 
 
156
                fn_info = (struct gcov_fn_info*)
 
157
                        SKIBOOT_ADDR(addr, functions[fn]);
 
158
 
 
159
                printf("function: %p\n", (void*)be64toh((u64)functions[fn]));
 
160
 
 
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));
 
166
 
 
167
                ctr_info = (struct gcov_ctr_info*)
 
168
                        ((char*)fn_info + sizeof(struct gcov_fn_info));
 
169
 
 
170
                for(ctr = 0; ctr < GCOV_COUNTERS; ctr++) {
 
171
                        if (!counter_active(gi, ctr))
 
172
                                continue;
 
173
 
 
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));
 
178
 
 
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]));
 
184
                        }
 
185
                        ctr_info++;
 
186
                }
 
187
        }
 
188
 
 
189
        close(fd);
 
190
}
 
191
 
 
192
 
 
193
int main(int argc, char *argv[])
 
194
{
 
195
        int r;
 
196
        int fd;
 
197
        struct stat sb;
 
198
        char *addr;
 
199
        u64 gcov_list_addr;
 
200
 
 
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);
 
208
 
 
209
        if (argc < 3) {
 
210
                fprintf(stderr, "Usage:\n"
 
211
                        "\t%s skiboot.dump gcov_offset\n\n",
 
212
                        argv[0]);
 
213
                return -1;
 
214
        }
 
215
 
 
216
        /* argv[1] = skiboot.dump */
 
217
        fd = open(argv[1], O_RDONLY);
 
218
        if (fd < 0) {
 
219
                fprintf(stderr, "Cannot open dump: %s (error %d %s)\n",
 
220
                        argv[1], errno, strerror(errno));
 
221
                exit(-1);
 
222
        }
 
223
 
 
224
        r = fstat(fd, &sb);
 
225
        if (r < 0) {
 
226
                fprintf(stderr, "Cannot stat dump, %d %s\n",
 
227
                        errno, strerror(errno));
 
228
                exit(-1);
 
229
        }
 
230
 
 
231
        addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 
232
        assert(addr != NULL);
 
233
        skiboot_dump_size = sb.st_size;
 
234
 
 
235
        printf("Skiboot memory dump %p - %p\n",
 
236
               (void*)SKIBOOT_OFFSET, (void*)SKIBOOT_OFFSET+sb.st_size);
 
237
 
 
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);
 
241
 
 
242
        printf("Skiboot gcov_info_list at %p\n", (void*)gcov_list_addr);
 
243
 
 
244
        do {
 
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);
 
248
 
 
249
        } while(gcov_list_addr);
 
250
 
 
251
        munmap(addr, sb.st_size);
 
252
        close(fd);
 
253
 
 
254
        return 0;
 
255
}