2 * Copyright (C) 2021, Ivanov Arkady <arkadiy.ivanov@ispras.ru>
4 * Drcov - a DynamoRIO-based tool that collects coverage information
5 * from a binary. Primary goal this script is to have coverage log
6 * files that work in Lighthouse.
8 * License: GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
21 #include <qemu-plugin.h>
23 QEMU_PLUGIN_EXPORT
int qemu_plugin_version
= QEMU_PLUGIN_VERSION
;
25 static char header
[] = "DRCOV VERSION: 2\n"
26 "DRCOV FLAVOR: drcov-64\n"
27 "Module Table: version 2, count 1\n"
28 "Columns: id, base, end, entry, path\n";
31 static const char *file_name
= "file.drcov.trace";
41 /* Translated blocks */
42 static GPtrArray
*blocks
;
44 static void printf_header(unsigned long count
)
46 fprintf(fp
, "%s", header
);
47 const char *path
= qemu_plugin_path_to_binary();
48 uint64_t start_code
= qemu_plugin_start_code();
49 uint64_t end_code
= qemu_plugin_end_code();
50 uint64_t entry
= qemu_plugin_entry_code();
51 fprintf(fp
, "0, 0x%lx, 0x%lx, 0x%lx, %s\n",
52 start_code
, end_code
, entry
, path
);
53 fprintf(fp
, "BB Table: %ld bbs\n", count
);
56 static void printf_char_array32(uint32_t data
)
58 const uint8_t *bytes
= (const uint8_t *)(&data
);
59 fwrite(bytes
, sizeof(char), sizeof(data
), fp
);
62 static void printf_char_array16(uint16_t data
)
64 const uint8_t *bytes
= (const uint8_t *)(&data
);
65 fwrite(bytes
, sizeof(char), sizeof(data
), fp
);
69 static void printf_el(gpointer data
, gpointer user_data
)
71 bb_entry_t
*bb
= (bb_entry_t
*)data
;
73 printf_char_array32(bb
->start
);
74 printf_char_array16(bb
->size
);
75 printf_char_array16(bb
->mod_id
);
80 static void count_block(gpointer data
, gpointer user_data
)
82 unsigned long *count
= (unsigned long *) user_data
;
83 bb_entry_t
*bb
= (bb_entry_t
*)data
;
89 static void plugin_exit(qemu_plugin_id_t id
, void *p
)
91 unsigned long count
= 0;
93 g_ptr_array_foreach(blocks
, count_block
, &count
);
97 g_ptr_array_foreach(blocks
, printf_el
, NULL
);
100 g_ptr_array_free(blocks
, true);
104 g_mutex_unlock(&lock
);
107 static void plugin_init(void)
109 fp
= fopen(file_name
, "wb");
110 blocks
= g_ptr_array_sized_new(128);
113 static void vcpu_tb_exec(unsigned int cpu_index
, void *udata
)
115 bb_entry_t
*bb
= (bb_entry_t
*) udata
;
119 g_mutex_unlock(&lock
);
122 static void vcpu_tb_trans(qemu_plugin_id_t id
, struct qemu_plugin_tb
*tb
)
124 uint64_t pc
= qemu_plugin_tb_vaddr(tb
);
125 size_t n
= qemu_plugin_tb_n_insns(tb
);
129 bb_entry_t
*bb
= g_new0(bb_entry_t
, 1);
130 for (int i
= 0; i
< n
; i
++) {
131 bb
->size
+= qemu_plugin_insn_size(qemu_plugin_tb_get_insn(tb
, i
));
137 g_ptr_array_add(blocks
, bb
);
139 g_mutex_unlock(&lock
);
140 qemu_plugin_register_vcpu_tb_exec_cb(tb
, vcpu_tb_exec
,
141 QEMU_PLUGIN_CB_NO_REGS
,
147 int qemu_plugin_install(qemu_plugin_id_t id
, const qemu_info_t
*info
,
148 int argc
, char **argv
)
150 for (int i
= 0; i
< argc
; i
++) {
151 g_autofree
char **tokens
= g_strsplit(argv
[i
], "=", 2);
152 if (g_strcmp0(tokens
[0], "filename") == 0) {
153 file_name
= g_strdup(tokens
[1]);
159 qemu_plugin_register_vcpu_tb_trans_cb(id
, vcpu_tb_trans
);
160 qemu_plugin_register_atexit_cb(id
, plugin_exit
, NULL
);