-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathd.c
116 lines (93 loc) · 3.19 KB
/
d.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-License-Identifier: 0BSD
#include <stdio.h>
#include <qemu-plugin.h>
enum {
INSN,
MEM_R,
MEM_W,
};
typedef struct Packet {
uint64_t vaddr;
uint32_t type;
uint32_t data;
} Packet;
typedef struct PacketList PacketList;
struct PacketList {
PacketList *next;
Packet packets[];
};
static FILE *file;
static PacketList *insn_packet_list;
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
static void plugin_vcpu_insn_exec(G_GNUC_UNUSED unsigned int vcpu_index,
void *userdata)
{
fwrite(userdata, sizeof(Packet), 1, file);
}
static void plugin_vcpu_mem(G_GNUC_UNUSED unsigned int vcpu_index,
qemu_plugin_meminfo_t info, uint64_t vaddr,
G_GNUC_UNUSED void *userdata)
{
Packet packet = {
.vaddr = GUINT64_TO_LE(vaddr),
.type = GUINT32_TO_LE(qemu_plugin_mem_is_store(info) ? MEM_W : MEM_R),
.data = GUINT32_TO_LE(qemu_plugin_mem_size_shift(info))
};
fwrite(&packet, sizeof(packet), 1, file);
}
static void plugin_vcpu_tb_trans(G_GNUC_UNUSED qemu_plugin_id_t id,
struct qemu_plugin_tb *tb)
{
size_t n = qemu_plugin_tb_n_insns(tb);
PacketList *list = malloc(sizeof(PacketList) + sizeof(Packet) * n);
list->next = insn_packet_list;
insn_packet_list = list;
for (size_t i = 0; i < n; i++) {
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
list->packets[i].vaddr = GUINT64_TO_LE(qemu_plugin_insn_vaddr(insn));
list->packets[i].type = GUINT32_TO_LE(INSN);
list->packets[i].data = 0;
qemu_plugin_insn_data(insn, &list->packets[i].data,
sizeof(list->packets[i].data));
qemu_plugin_register_vcpu_insn_exec_cb(insn, plugin_vcpu_insn_exec,
QEMU_PLUGIN_CB_NO_REGS,
list->packets + i);
qemu_plugin_register_vcpu_mem_cb(insn, plugin_vcpu_mem,
QEMU_PLUGIN_CB_NO_REGS,
QEMU_PLUGIN_MEM_RW, NULL);
}
}
static void plugin_flush(G_GNUC_UNUSED qemu_plugin_id_t id)
{
while (insn_packet_list) {
PacketList *prev = insn_packet_list;
insn_packet_list = insn_packet_list->next;
free(prev);
}
}
static void plugin_atexit(qemu_plugin_id_t id, G_GNUC_UNUSED void *userdata)
{
plugin_flush(id);
fclose(file);
}
QEMU_PLUGIN_EXPORT
int qemu_plugin_install(qemu_plugin_id_t id,
G_GNUC_UNUSED const qemu_info_t *info,
int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
if (memcmp(argv[i], "outfile=", sizeof("outfile=") - 1)) {
fputs("unknown option\n", stderr);
return -1;
}
file = fopen(argv[i] + sizeof("outfile=") - 1, "w");
if (!file) {
perror("outfile");
return -1;
}
}
qemu_plugin_register_vcpu_tb_trans_cb(id, plugin_vcpu_tb_trans);
qemu_plugin_register_flush_cb(id, plugin_flush);
qemu_plugin_register_atexit_cb(id, plugin_atexit, NULL);
return 0;
}