2
* Copyright (C) 2010 Simon Kagstrom, Thomas Neumann
4
* See COPYING for license details
11
#include <sys/fcntl.h>
15
#include <libgen.h> /* POSIX basename */
23
static gint cmp_line(gconstpointer _a, gconstpointer _b)
25
const struct kc_line *a = _a;
26
const struct kc_line *b = _b;
29
ret = strcmp(a->file->filename, b->file->filename) == 0;
31
ret = (a->lineno - b->lineno) == 0;
36
static guint hash_line(gconstpointer _a)
38
const struct kc_line *a = _a;
40
return g_str_hash(a->file->filename) + g_int_hash(&a->lineno);
44
void kc_add_addr(struct kc *kc, unsigned long addr_in, int line_nr, const char *filename)
46
struct kc_line *table_line;
51
file = g_hash_table_lookup(kc->files, filename);
53
file = kc_file_new(filename);
54
g_hash_table_insert(kc->files, (gpointer*)file->filename, file);
57
line = kc_line_new(file, line_nr);
58
table_line = g_hash_table_lookup(kc->lines, line);
65
addr = kc_addr_new(addr_in);
67
g_hash_table_insert(kc->lines, line, line);
68
g_hash_table_insert(kc->addrs, (gpointer*)&addr->addr, addr);
70
kc_line_add_addr(line, addr);
71
kc_file_add_line(file, line);
74
struct kc_addr *kc_lookup_addr(struct kc *kc, unsigned long addr)
76
return g_hash_table_lookup(kc->addrs, (gpointer *)&addr);
80
static void dwarf_error_handler(Dwarf_Error error, Dwarf_Ptr userData)
82
char *msg = dwarf_errmsg(error);
84
printf("Dwarf: %s\n", msg);
87
static int lookup_elf_type(struct kc *kc, const char *filename, struct Elf *elf)
95
kc->type = PTRACE_FILE;
96
if (!elf_getshdrstrndx(elf, &shstrndx) < 0)
99
hdr32 = elf32_getehdr(elf);
100
hdr64 = elf64_getehdr(elf);
101
if (hdr32 == NULL && hdr64 == NULL) {
102
error("Can't get elf header\n");
105
if (hdr32 != NULL && hdr64 != NULL) {
106
error("Both 32- and 64-bit???\n");
110
is_32 = hdr32 != NULL;
112
kc->e_machine = (unsigned int)hdr32->e_machine;
114
kc->e_machine = (unsigned int)hdr64->e_machine;
116
while ( (scn = elf_nextscn(elf, scn)) != NULL ) {
120
Elf32_Shdr *shdr = elf32_getshdr(scn);
125
name = elf_strptr(elf, shstrndx, shdr->sh_name);
128
Elf64_Shdr *shdr = elf64_getshdr(scn);
133
name = elf_strptr(elf, shstrndx, shdr->sh_name);
136
/* Linux kernel module? */
137
if (strcmp(name, ".modinfo") == 0) {
138
char *cpy = xstrdup(filename);
139
char *bn = xstrdup(basename(cpy));
142
/* Remove .ko and fixup module names */
143
p = strrchr(bn, '.');
146
for (p = bn; *p; p++) {
151
free((void *)kc->module_name);
152
kc->type = KPROBE_COVERAGE;
153
kc->module_name = bn;
158
else if (strcmp(name, "__ksymtab") == 0) {
159
kc->type = KPROBE_COVERAGE;
167
static const char *lookup_filename_by_pid(pid_t pid)
169
char linkpath[80 + 1];
173
memset(path, 0, sizeof(path));
174
snprintf(linkpath, sizeof(linkpath) - 1, "/proc/%d/exe", pid);
175
linkpath[sizeof(linkpath) - 1 ] = '\0';
177
err = readlink(linkpath, path, sizeof(path));
181
/* This allocation will be lost, but that's OK - this function
182
* is only called once at startup anyway. */
183
return xstrdup(path);
186
struct kc *kc_open_elf(const char *filename, pid_t pid)
188
Dwarf_Unsigned header;
195
if (pid != 0 && filename == NULL) {
196
filename = lookup_filename_by_pid(pid);
199
error("Can't lookup filename of PID %d\n", pid);
204
fd = open(filename, O_RDONLY);
208
/* Initialize libdwarf */
209
err = dwarf_init(fd, DW_DLC_READ, dwarf_error_handler, 0, &dbg,0);
210
if (err == DW_DLV_ERROR) {
215
/* Zeroes everything */
216
kc = xmalloc(sizeof(struct kc));
217
kc->module_name = xstrdup("");
218
kc->in_file = filename;
220
kc->addrs = g_hash_table_new(g_int_hash, g_int_equal);
221
kc->lines = g_hash_table_new(hash_line, cmp_line);
222
kc->files = g_hash_table_new(g_str_hash, g_str_equal);
223
kc->sort_type = FILENAME;
225
if (err == DW_DLV_NO_ENTRY)
228
err = dwarf_get_elf(dbg, &elf, NULL);
229
err = lookup_elf_type(kc, filename, elf);
233
kc->type = PTRACE_PID;
235
/* Iterate over the headers */
236
while (dwarf_next_cu_header(dbg, 0, 0, 0, 0,
237
&header, 0) == DW_DLV_OK) {
238
Dwarf_Line* line_buffer;
239
Dwarf_Signed line_count;
243
if (dwarf_siblingof(dbg, 0, &die, 0) != DW_DLV_OK)
246
/* Get the source lines */
247
if (dwarf_srclines(die, &line_buffer, &line_count, 0) != DW_DLV_OK)
251
for (i = 0; i < line_count; i++) {
252
Dwarf_Unsigned line_nr;
257
if (dwarf_lineno(line_buffer[i], &line_nr, 0) != DW_DLV_OK)
259
if (dwarf_linesrc(line_buffer[i], &line_source, 0) != DW_DLV_OK)
261
if (dwarf_linebeginstatement(line_buffer[i], &is_code, 0) != DW_DLV_OK)
264
if (dwarf_lineaddr(line_buffer[i], &addr, 0) != DW_DLV_OK)
267
if (line_nr && is_code) {
268
kc_add_addr(kc, addr, line_nr, line_source);
271
dwarf_dealloc(dbg, line_source, DW_DLA_STRING);
274
/* Release the memory */
275
for (i = 0; i < line_count; i++)
276
dwarf_dealloc(dbg,line_buffer[i], DW_DLA_LINE);
277
dwarf_dealloc(dbg,line_buffer, DW_DLA_LIST);
280
/* Shutdown libdwarf */
281
if (dwarf_finish(dbg, 0) != DW_DLV_OK)
296
void kc_close(struct kc *kc)
303
static uint64_t get_file_checksum(struct kc *kc)
307
if (lstat(kc->in_file, &st) < 0)
310
return ((uint64_t)st.st_mtim.tv_sec << 32) | ((uint64_t)st.st_mtim.tv_nsec);
313
void kc_db_marshal(struct kc_data_db *db)
317
void kc_db_unmarshal(struct kc_data_db *db)
321
void kc_read_db(struct kc *kc)
323
struct kc_data_db *db;
328
db = read_file(&sz, "%s/%s/kcov.db", kc->out_dir, kc->binary_filename);
332
checksum = get_file_checksum(kc);
333
if (db->elf_checksum != checksum)
336
for (i = 0; i < db->n_addrs; i++) {
337
struct kc_addr *db_addr = &db->addrs[i];
340
kc_addr_unmarshall(db_addr);
342
tgt = kc_lookup_addr(kc, db_addr->addr);
346
tgt->hits += db_addr->hits;
353
void kc_write_db(struct kc *kc)
355
struct kc_data_db *db;
362
sz = g_hash_table_size(kc->addrs);
363
db = xmalloc(sizeof(struct kc_data_db) + sizeof(struct kc_addr) * sz);
365
db->elf_checksum = get_file_checksum(kc);
367
g_hash_table_iter_init(&iter, kc->addrs);
368
while (g_hash_table_iter_next(&iter, (gpointer*)&key, (gpointer*)&val)) {
369
struct kc_addr *db_addr = &db->addrs[cnt];
371
memcpy(db_addr, val, sizeof(struct kc_addr));
372
kc_addr_marshall(db_addr);
377
write_file(db, sizeof(struct kc_data_db) + sz * sizeof(struct kc_addr),
378
"%s/%s/kcov.db", kc->out_dir, kc->binary_filename);
383
int kc_coverage_db_read(const char *dir, struct kc_coverage_db *dst)
385
struct kc_coverage_db *db;
388
db = read_file(&sz, "%s/kcov_coverage.db", dir);
391
if (sz != sizeof(struct kc_coverage_db)) {
392
warning("Coverage db size wrong: %u vs %u\n",
393
sz, sizeof(struct kc_coverage_db));
399
kc_coverage_db_unmarshal(dst);
405
void kc_coverage_db_write(const char *dir, struct kc_coverage_db *src)
407
struct kc_coverage_db db;
410
kc_coverage_db_marshal(&db);
412
write_file(&db, sizeof(struct kc_coverage_db),
413
"%s/kcov_coverage.db", dir);
416
void kc_coverage_db_marshal(struct kc_coverage_db *db)
420
void kc_coverage_db_unmarshal(struct kc_coverage_db *db)