Skip to content

Commit f88cb26

Browse files
committed
Write meta frames and add outputfile argument.
1 parent 4608ba4 commit f88cb26

File tree

6 files changed

+133
-53
lines changed

6 files changed

+133
-53
lines changed

contrib/plugins/bap-tracing/frame_buffer.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ bool frame_buffer_is_full(const FrameBuffer *buf) {
9898

9999
void frame_buffer_close_frame(FrameBuffer *buf) {
100100
char *str = frame_buffer_as_str(buf);
101-
qemu_plugin_outs("Close frame: ");
102-
qemu_plugin_outs(str);
103-
qemu_plugin_outs("\n\n");
101+
// qemu_plugin_outs("Close frame: ");
102+
// qemu_plugin_outs(str);
103+
// qemu_plugin_outs("\n\n");
104104
g_free(str);
105105
buf->idx++;
106106
}

contrib/plugins/bap-tracing/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dep_libprotobuf = declare_dependency(
4141
bap_tracing_src = files(
4242
'frame_buffer.c',
4343
'tracing.c',
44+
'trace_meta.c',
4445
)
4546

4647
if host_os == 'windows'

contrib/plugins/bap-tracing/trace_consts.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef BAP_TRACE_CONSTS_H
22
#define BAP_TRACE_CONSTS_H
33

4+
#include "qemu-version.h"
45
#include <stdint.h>
56

67
// Trace header constants
@@ -18,6 +19,9 @@ static const uint64_t offset_first_frame = 48LL;
1819

1920
static const uint64_t trace_version = 3LL;
2021

22+
#define TRACER_NAME "qemu"
23+
#define TRACER_VERSION "plugin " QEMU_FULL_VERSION
24+
2125
#define FRAMES_PER_TOC_ENTRY_ 64LL
2226
static const uint64_t frames_per_toc_entry = FRAMES_PER_TOC_ENTRY_;
2327

contrib/plugins/bap-tracing/trace_meta.c

Lines changed: 108 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
#include <sys/stat.h>
88

99
#include "frame.piqi.pb-c-patched.h"
10+
#include "trace_consts.h"
1011
#include "trace_meta.h"
1112

1213
#define MD5LEN 16
1314

14-
static void compute_target_md5(const char *binary_path) {
15+
static void compute_target_md5(const char *binary_path,
16+
guchar target_md5[MD5LEN]) {
1517
const GChecksumType md5 = G_CHECKSUM_MD5;
16-
guchar target_md5[MD5LEN];
1718

1819
GChecksum *cs = g_checksum_new(md5);
1920
FILE *target = fopen(binary_path, "r");
@@ -38,37 +39,31 @@ static void compute_target_md5(const char *binary_path) {
3839
fclose(target);
3940
}
4041

41-
static void meta_write_header(FILE *file) {
42-
// uint64_t toc_off = 0L;
43-
// WRITE(magic_number);
44-
// WRITE(out_trace_version);
45-
// WRITE(frame_arch);
46-
// WRITE(frame_mach);
47-
// WRITE(toc_num_frames);
48-
// WRITE(toc_off);
42+
static void init_tracer(Tracer *tracer, char **argv, int argc) {
43+
tracer__init(tracer);
44+
tracer->name = g_strdup(TRACER_NAME);
45+
tracer->n_args = argc;
46+
tracer->args = argv;
47+
tracer->n_envp = 0;
48+
tracer->envp = NULL;
49+
tracer->version = g_strdup(TRACER_VERSION);
4950
}
5051

51-
static void init_tracer(Tracer *tracer, char **argv, char **envp) {
52-
// tracer__init(tracer);
53-
// tracer->name = tracer_name;
54-
// tracer->n_args = list_length(argv);
55-
// tracer->args = argv;
56-
// tracer->n_envp = list_length(envp);
57-
// tracer->envp = envp;
58-
// tracer->version = tracer_version;
59-
}
52+
static void init_target(Target *target, const char *bin_path, char **argv,
53+
int argc) {
54+
target__init(target);
6055

61-
static void init_target(Target *target, char **argv, char **envp) {
62-
// compute_target_md5();
63-
64-
// target__init(target);
65-
// target->path = target_path;
66-
// target->n_args = list_length(argv);
67-
// target->args = argv;
68-
// target->n_envp = list_length(envp);
69-
// target->envp = envp;
70-
// target->md5sum.len = MD5LEN;
71-
// target->md5sum.data = target_md5;
56+
if (bin_path) {
57+
guchar *target_md5 = g_malloc0(MD5LEN);
58+
compute_target_md5(bin_path, target_md5);
59+
target->path = g_strdup(bin_path);
60+
target->md5sum.len = MD5LEN;
61+
target->md5sum.data = target_md5;
62+
}
63+
target->n_args = argc;
64+
target->args = argv;
65+
target->n_envp = 0;
66+
target->envp = NULL;
7267
}
7368

7469
#ifdef G_OS_UNIX
@@ -95,18 +90,74 @@ static bool init_fstats(Fstats *fstats, const char *binary_path) {
9590
return true;
9691
}
9792

98-
static void write_meta(WLOCKED FILE *file, char **tracer_argv,
99-
char **tracer_envp, char **target_argv,
100-
char **target_envp) {
101-
MetaFrame meta;
102-
Tracer tracer;
103-
Target target;
104-
Fstats fstats;
93+
char *get_argv_val(char **argv, int argc, const char *key) {
94+
for (size_t i = 0; i < argc; ++i) {
95+
if (!strncmp(argv[i], key, strlen(key))) {
96+
const char *val = argv[i] + strlen(key);
97+
if (val[0] != '=') {
98+
qemu_plugin_outs("Invalid argument value for ");
99+
qemu_plugin_outs(key);
100+
qemu_plugin_outs("\n");
101+
qemu_plugin_outs("Should be 'key=val'\n");
102+
return NULL;
103+
}
104+
val++;
105+
const char *end = strchr(val, ',');
106+
while (end && *(end - 1) == '\\') {
107+
// Allow escaped commas.
108+
end = strchr(val, ',');
109+
}
110+
size_t len = !end ? strlen(val) : end - val;
111+
char *argument = g_malloc0(len + 1);
112+
memcpy(argument, val, len);
113+
return argument;
114+
}
115+
}
116+
return NULL;
117+
}
118+
119+
void file_exists_exit(const char *file) {
120+
FILE *test = fopen(file, "r");
121+
if (!test) {
122+
qemu_plugin_outs("Failed to open binary file: ");
123+
qemu_plugin_outs(file);
124+
qemu_plugin_outs("\n");
125+
exit(1);
126+
}
127+
fclose(test);
128+
}
129+
130+
void write_meta(WLOCKED FILE *file, char **plugin_argv, size_t plugin_argc) {
131+
char *arg_bin_path = get_argv_val(plugin_argv, plugin_argc, "bin_path");
132+
// Note: Usually we should get the binary path from
133+
// qemu_plugin_path_to_binary(). But it doesn't seem to work due to dependency
134+
// issues. See: https://gitlab.com/qemu-project/qemu/-/issues/3014
135+
const char *bin_path = NULL; // qemu_plugin_path_to_binary();
136+
if (!bin_path && !arg_bin_path) {
137+
qemu_plugin_outs("\nFailed to retrieve the binary path\n");
138+
qemu_plugin_outs("This is required.\n");
139+
qemu_plugin_outs("You can pass it as plugin argument "
140+
"'bin_path=<path>'.\n\n");
141+
exit(1);
142+
} else {
143+
file_exists_exit(arg_bin_path);
144+
}
145+
if (bin_path && arg_bin_path) {
146+
qemu_plugin_outs(
147+
"'bin_path' argument found, but the binary path is known to the module.\n\
148+
Argument 'bin_path' is ignored.\n");
149+
}
150+
151+
MetaFrame meta = {0};
152+
Tracer tracer = {0};
153+
Target target = {0};
154+
Fstats fstats = {0};
105155

106156
meta_frame__init(&meta);
107-
init_tracer(&tracer, tracer_argv, tracer_envp);
108-
init_target(&target, target_argv, target_envp);
109-
init_fstats(&fstats, "target-path");
157+
init_tracer(&tracer, plugin_argv, plugin_argc);
158+
init_target(&target, bin_path ? bin_path : arg_bin_path, plugin_argv,
159+
plugin_argc);
160+
init_fstats(&fstats, bin_path ? bin_path : arg_bin_path);
110161

111162
meta.tracer = &tracer;
112163
meta.target = &target;
@@ -119,11 +170,24 @@ static void write_meta(WLOCKED FILE *file, char **tracer_argv,
119170
meta.host = host;
120171

121172
size_t msg_size = meta_frame__get_packed_size(&meta);
122-
uint8_t *packed_buffer = g_alloca(msg_size);
173+
uint8_t *packed_buffer = g_malloc0(msg_size);
123174
uint64_t packed_size = meta_frame__pack(&meta, packed_buffer);
175+
g_assert(msg_size == packed_size);
124176
WRITE(packed_size);
125-
WRITE_BUF(&meta, packed_size);
126177

127-
free(user);
128-
free(host);
178+
// I don't know why, but ASAN crashes at this line if the WRITE_BUF macro
179+
// is used. Although it should be the exact same code.
180+
if (fwrite((packed_buffer), 1, (packed_size), file) != packed_size) {
181+
err(1, "fwrite failed");
182+
}
183+
184+
g_free(packed_buffer);
185+
g_free(tracer.name);
186+
g_free(tracer.version);
187+
g_free(target.path);
188+
g_free(target.md5sum.data);
189+
190+
g_free(user);
191+
g_free(host);
192+
g_free(arg_bin_path);
129193
}

contrib/plugins/bap-tracing/trace_meta.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define BAP_TRACE_META_H
66

77
#include <err.h>
8+
#include <stdio.h>
89

910
/**
1011
* \brief Empty macros indicate the argument, variable etc.
@@ -30,4 +31,8 @@
3031
err(1, "stream not seekable"); \
3132
} while (0)
3233

34+
void write_meta(WLOCKED FILE *file, char **plugin_argv, size_t plugin_argc);
35+
char *get_argv_val(char **argv, int argc, const char *key);
36+
void file_exists_exit(const char *file);
37+
3338
#endif

contrib/plugins/bap-tracing/tracing.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <glib.h>
55
#include <stdio.h>
6+
#include <string.h>
67

78
#include "frame_arch.h"
89
#include "frame_buffer.h"
@@ -230,6 +231,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *udata) {
230231
g_rw_lock_reader_unlock(&state.total_num_frames_lock);
231232
g_rw_lock_reader_unlock(&state.toc_entries_offsets_lock);
232233
g_rw_lock_writer_unlock(&state.file_lock);
234+
qemu_plugin_outs("Finished trace\n");
233235
}
234236

235237
static bool get_frame_arch_mach(const char *target_name, uint64_t *arch,
@@ -271,24 +273,28 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
271273
qemu_plugin_outs("Target name: ");
272274
qemu_plugin_outs(info->target_name);
273275
qemu_plugin_outs("\n");
276+
char *output = get_argv_val(argv, argc, "out");
277+
if (!output) {
278+
qemu_plugin_outs("'out' argument is missing.\n");
279+
qemu_plugin_outs("This is required.\n");
280+
qemu_plugin_outs("Pass it with 'out=<output_file>'.\n\n");
281+
exit(1);
282+
}
274283

275-
const char *target_path = "/tmp/test.trace";
276284
state.frame_buffer = g_ptr_array_new();
277285
state.toc_entries_offsets = g_array_new(false, true, sizeof(uint64_t));
278286
state.vcpus = g_ptr_array_new();
279-
state.file = fopen(target_path, "wb");
287+
state.file = fopen(output, "wb");
280288
if (!(state.frame_buffer || state.vcpus || state.file ||
281289
!state.toc_entries_offsets)) {
282290
return 1;
283291
}
284-
for (size_t i = 0; i < argc; ++i) {
285-
qemu_plugin_outs(argv[i]);
286-
}
292+
g_free(output);
287293
if (!write_header(state.file, info->target_name)) {
288294
qemu_plugin_outs("Failed to header.\n");
289295
return 1;
290296
}
291-
// write_meta(argv, envp, target_argv, target_envp);
297+
write_meta(state.file, argv, argc);
292298

293299
g_array_append_val(state.toc_entries_offsets, offset_toc_start);
294300

0 commit comments

Comments
 (0)