Commit | Line | Data |
---|---|---|
4f45f9bb JD |
1 | /* |
2 | * copy.c | |
3 | * | |
4 | * Babeltrace Copy Trace Structure | |
5 | * | |
6 | * Copyright 2017 Julien Desfossez <jdesfossez@efficios.com> | |
7 | * | |
8 | * Author: Julien Desfossez <jdesfossez@efficios.com> | |
9 | * | |
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
11 | * of this software and associated documentation files (the "Software"), to deal | |
12 | * in the Software without restriction, including without limitation the rights | |
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
14 | * copies of the Software, and to permit persons to whom the Software is | |
15 | * furnished to do so, subject to the following conditions: | |
16 | * | |
17 | * The above copyright notice and this permission notice shall be included in | |
18 | * all copies or substantial portions of the Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
26 | * SOFTWARE. | |
27 | */ | |
28 | ||
b4d4912f JD |
29 | #define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-FLT-COPY" |
30 | #include "logging.h" | |
31 | ||
4f45f9bb | 32 | #include <inttypes.h> |
b4d4912f | 33 | #include <assert.h> |
4f45f9bb JD |
34 | #include <babeltrace/ctf-ir/event.h> |
35 | #include <babeltrace/ctf-ir/packet.h> | |
36 | #include <babeltrace/ctf-ir/event-class.h> | |
37 | #include <babeltrace/ctf-ir/stream.h> | |
38 | #include <babeltrace/ctf-ir/stream-class.h> | |
39 | #include <babeltrace/ctf-ir/clock-class.h> | |
40 | #include <babeltrace/ctf-ir/fields.h> | |
41 | #include <babeltrace/ctf-writer/stream-class.h> | |
42 | #include <babeltrace/ctf-writer/stream.h> | |
43 | ||
44 | #include <ctfcopytrace.h> | |
45 | #include "debug-info.h" | |
46 | ||
cb0a5cf8 JD |
47 | static |
48 | struct bt_ctf_stream *insert_new_stream( | |
49 | struct debug_info_iterator *debug_it, | |
50 | struct bt_ctf_stream *stream, | |
51 | struct debug_info_trace *di_trace); | |
52 | ||
504db471 JD |
53 | static |
54 | void unref_stream(struct bt_ctf_stream *stream) | |
55 | { | |
56 | bt_put(stream); | |
57 | } | |
58 | ||
59 | static | |
60 | void unref_packet(struct bt_ctf_packet *packet) | |
61 | { | |
62 | bt_put(packet); | |
63 | } | |
64 | ||
65 | static | |
66 | void unref_stream_class(struct bt_ctf_stream_class *stream_class) | |
67 | { | |
68 | bt_put(stream_class); | |
69 | } | |
70 | ||
71 | static | |
72 | void unref_debug_info(struct debug_info *debug_info) | |
73 | { | |
74 | debug_info_destroy(debug_info); | |
75 | } | |
76 | ||
1c78e839 JD |
77 | static |
78 | void destroy_stream_state_key(gpointer key) | |
79 | { | |
80 | g_free((enum fs_writer_stream_state *) key); | |
81 | } | |
82 | ||
4f45f9bb JD |
83 | static |
84 | struct bt_ctf_field *get_payload_field(FILE *err, | |
85 | struct bt_ctf_event *event, const char *field_name) | |
86 | { | |
b4d4912f JD |
87 | struct bt_ctf_field *field = NULL, *payload = NULL; |
88 | struct bt_ctf_field_type *payload_type = NULL; | |
4f45f9bb | 89 | |
b4d4912f JD |
90 | payload = bt_ctf_event_get_payload(event, NULL); |
91 | assert(payload); | |
4f45f9bb | 92 | |
b4d4912f JD |
93 | payload_type = bt_ctf_field_get_type(payload); |
94 | assert(payload_type); | |
4f45f9bb | 95 | |
b4d4912f JD |
96 | if (bt_ctf_field_type_get_type_id(payload_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { |
97 | BT_LOGE("Wrong type, expected struct: field-name=\"%s\"", | |
98 | field_name); | |
4f45f9bb JD |
99 | goto end; |
100 | } | |
101 | ||
b4d4912f | 102 | field = bt_ctf_field_structure_get_field(payload, field_name); |
4f45f9bb JD |
103 | |
104 | end: | |
b4d4912f JD |
105 | bt_put(payload_type); |
106 | bt_put(payload); | |
4f45f9bb JD |
107 | return field; |
108 | } | |
109 | ||
110 | static | |
111 | struct bt_ctf_field *get_stream_event_context_field(FILE *err, | |
112 | struct bt_ctf_event *event, const char *field_name) | |
113 | { | |
114 | struct bt_ctf_field *field = NULL, *sec = NULL; | |
115 | struct bt_ctf_field_type *sec_type = NULL; | |
116 | ||
117 | sec = bt_ctf_event_get_stream_event_context(event); | |
118 | if (!sec) { | |
4f45f9bb JD |
119 | goto end; |
120 | } | |
121 | ||
122 | sec_type = bt_ctf_field_get_type(sec); | |
b4d4912f | 123 | assert(sec_type); |
4f45f9bb | 124 | |
1487a16a | 125 | if (bt_ctf_field_type_get_type_id(sec_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { |
b4d4912f JD |
126 | BT_LOGE("Wrong type, expected struct, field-name=\"%s\"", |
127 | field_name); | |
4f45f9bb JD |
128 | goto end; |
129 | } | |
130 | ||
131 | field = bt_ctf_field_structure_get_field(sec, field_name); | |
132 | ||
133 | end: | |
134 | bt_put(sec_type); | |
135 | bt_put(sec); | |
136 | return field; | |
137 | } | |
138 | ||
139 | BT_HIDDEN | |
140 | int get_stream_event_context_unsigned_int_field_value(FILE *err, | |
141 | struct bt_ctf_event *event, const char *field_name, | |
142 | uint64_t *value) | |
143 | { | |
144 | int ret; | |
145 | struct bt_ctf_field *field = NULL; | |
146 | struct bt_ctf_field_type *field_type = NULL; | |
147 | ||
148 | field = get_stream_event_context_field(err, event, field_name); | |
149 | if (!field) { | |
4f45f9bb JD |
150 | goto error; |
151 | } | |
152 | ||
153 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 154 | assert(field_type); |
4f45f9bb | 155 | |
1487a16a | 156 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { |
b4d4912f JD |
157 | BT_LOGE("Wrong type, expected integer: field-name=\"%s\"", |
158 | field_name); | |
4f45f9bb JD |
159 | goto error; |
160 | } | |
161 | ||
162 | if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { | |
b4d4912f JD |
163 | BT_LOGE("Wrong type, expected unsigned integer: field-name=\"%s\"", |
164 | field_name); | |
4f45f9bb JD |
165 | goto error; |
166 | } | |
167 | ||
168 | ret = bt_ctf_field_unsigned_integer_get_value(field, value); | |
b4d4912f JD |
169 | if (ret) { |
170 | BT_LOGE("Failed to get value: field-name=\"%s\"", | |
171 | field_name); | |
172 | goto error; | |
173 | } | |
4f45f9bb JD |
174 | goto end; |
175 | ||
176 | error: | |
177 | ret = -1; | |
178 | end: | |
179 | bt_put(field_type); | |
180 | bt_put(field); | |
181 | return ret; | |
182 | } | |
183 | ||
184 | BT_HIDDEN | |
185 | int get_stream_event_context_int_field_value(FILE *err, struct bt_ctf_event *event, | |
186 | const char *field_name, int64_t *value) | |
187 | { | |
188 | struct bt_ctf_field *field = NULL; | |
189 | struct bt_ctf_field_type *field_type = NULL; | |
190 | int ret; | |
191 | ||
192 | field = get_stream_event_context_field(err, event, field_name); | |
193 | if (!field) { | |
194 | goto error; | |
195 | } | |
196 | ||
197 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 198 | assert(field_type); |
4f45f9bb | 199 | |
1487a16a | 200 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { |
b4d4912f | 201 | BT_LOGE("Wrong type, expected integer: field-name=\"%s\"", field_name); |
4f45f9bb JD |
202 | goto error; |
203 | } | |
204 | ||
205 | if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { | |
b4d4912f JD |
206 | BT_LOGE("Wrong type, expected signed integer: field-name=\"%s\"", |
207 | field_name); | |
4f45f9bb JD |
208 | goto error; |
209 | } | |
210 | ||
211 | ret = bt_ctf_field_signed_integer_get_value(field, value); | |
212 | goto end; | |
213 | ||
214 | error: | |
215 | ret = -1; | |
216 | end: | |
217 | bt_put(field_type); | |
218 | bt_put(field); | |
219 | return ret; | |
220 | } | |
221 | ||
222 | BT_HIDDEN | |
223 | int get_payload_unsigned_int_field_value(FILE *err, | |
224 | struct bt_ctf_event *event, const char *field_name, | |
225 | uint64_t *value) | |
226 | { | |
227 | struct bt_ctf_field *field = NULL; | |
228 | struct bt_ctf_field_type *field_type = NULL; | |
229 | int ret; | |
230 | ||
231 | field = get_payload_field(err, event, field_name); | |
232 | if (!field) { | |
b4d4912f | 233 | BT_LOGE("Failed to get payload: field-name=\"%s\"", field_name); |
4f45f9bb JD |
234 | goto error; |
235 | } | |
236 | ||
237 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 238 | assert(field_type); |
4f45f9bb | 239 | |
1487a16a | 240 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { |
b4d4912f JD |
241 | BT_LOGE("Wrong type, expected integer: field-name=\"%s\"", |
242 | field_name); | |
4f45f9bb JD |
243 | goto error; |
244 | } | |
245 | ||
246 | if (bt_ctf_field_type_integer_get_signed(field_type) != 0) { | |
b4d4912f JD |
247 | BT_LOGE("Wrong type, expected unsigned integer: field-name=\"%s\"", |
248 | field_name); | |
4f45f9bb JD |
249 | goto error; |
250 | } | |
251 | ||
252 | ret = bt_ctf_field_unsigned_integer_get_value(field, value); | |
b4d4912f JD |
253 | if (ret) { |
254 | BT_LOGE("Failed to get value: field-name=\"%s\"", | |
255 | field_name); | |
256 | goto error; | |
257 | } | |
4f45f9bb JD |
258 | goto end; |
259 | ||
260 | error: | |
261 | ret = -1; | |
262 | end: | |
263 | bt_put(field_type); | |
264 | bt_put(field); | |
265 | return ret; | |
266 | } | |
267 | ||
268 | BT_HIDDEN | |
269 | int get_payload_int_field_value(FILE *err, struct bt_ctf_event *event, | |
270 | const char *field_name, int64_t *value) | |
271 | { | |
272 | struct bt_ctf_field *field = NULL; | |
273 | struct bt_ctf_field_type *field_type = NULL; | |
274 | int ret; | |
275 | ||
276 | field = get_payload_field(err, event, field_name); | |
277 | if (!field) { | |
b4d4912f | 278 | BT_LOGE("Failed to get payload: field-name=\"%s\"", field_name); |
4f45f9bb JD |
279 | goto error; |
280 | } | |
281 | ||
282 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 283 | assert(field_type); |
4f45f9bb | 284 | |
1487a16a | 285 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) { |
b4d4912f | 286 | BT_LOGE("Wrong type, expected integer: field-name=\"%s\"", field_name); |
4f45f9bb JD |
287 | goto error; |
288 | } | |
289 | ||
290 | if (bt_ctf_field_type_integer_get_signed(field_type) != 1) { | |
b4d4912f JD |
291 | BT_LOGE("Wrong type, expected signed integer field-name=\"%s\"", |
292 | field_name); | |
4f45f9bb JD |
293 | goto error; |
294 | } | |
295 | ||
296 | ret = bt_ctf_field_signed_integer_get_value(field, value); | |
b4d4912f JD |
297 | if (ret) { |
298 | BT_LOGE("Failed to get value: field-name=\"%s\"", | |
299 | field_name); | |
300 | goto error; | |
301 | } | |
4f45f9bb JD |
302 | goto end; |
303 | ||
304 | error: | |
305 | ret = -1; | |
306 | end: | |
307 | bt_put(field_type); | |
308 | bt_put(field); | |
309 | return ret; | |
310 | } | |
311 | ||
312 | BT_HIDDEN | |
313 | int get_payload_string_field_value(FILE *err, | |
314 | struct bt_ctf_event *event, const char *field_name, | |
315 | const char **value) | |
316 | { | |
317 | struct bt_ctf_field *field = NULL; | |
318 | struct bt_ctf_field_type *field_type = NULL; | |
319 | int ret; | |
320 | ||
65db8b88 JD |
321 | /* |
322 | * The field might not exist, no error here. | |
323 | */ | |
4f45f9bb JD |
324 | field = get_payload_field(err, event, field_name); |
325 | if (!field) { | |
4f45f9bb JD |
326 | goto error; |
327 | } | |
328 | ||
329 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 330 | assert(field_type); |
4f45f9bb | 331 | |
1487a16a | 332 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_STRING) { |
b4d4912f JD |
333 | BT_LOGE("Wrong type, expected string: field-name=\"%s\"", |
334 | field_name); | |
4f45f9bb JD |
335 | goto error; |
336 | } | |
337 | ||
338 | *value = bt_ctf_field_string_get_value(field); | |
339 | if (!*value) { | |
b4d4912f JD |
340 | BT_LOGE("Failed to get value: field-name=\"%s\"", |
341 | field_name); | |
4f45f9bb JD |
342 | goto error; |
343 | } | |
344 | ||
345 | ret = 0; | |
346 | goto end; | |
347 | ||
348 | error: | |
349 | ret = -1; | |
350 | end: | |
351 | bt_put(field_type); | |
352 | bt_put(field); | |
353 | return ret; | |
354 | } | |
355 | ||
356 | BT_HIDDEN | |
357 | int get_payload_build_id_field_value(FILE *err, | |
358 | struct bt_ctf_event *event, const char *field_name, | |
359 | uint8_t **build_id, uint64_t *build_id_len) | |
360 | { | |
361 | struct bt_ctf_field *field = NULL, *seq_len = NULL; | |
362 | struct bt_ctf_field_type *field_type = NULL; | |
363 | struct bt_ctf_field *seq_field = NULL; | |
364 | uint64_t i; | |
365 | int ret; | |
366 | ||
367 | *build_id = NULL; | |
368 | ||
369 | field = get_payload_field(err, event, field_name); | |
370 | if (!field) { | |
b4d4912f | 371 | BT_LOGE("Failed to get payload: field-name=\"%s\"", field_name); |
4f45f9bb JD |
372 | goto error; |
373 | } | |
374 | ||
375 | field_type = bt_ctf_field_get_type(field); | |
b4d4912f | 376 | assert(field_type); |
4f45f9bb | 377 | |
1487a16a | 378 | if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_SEQUENCE) { |
b4d4912f | 379 | BT_LOGE("Wrong type, expected sequence: field-name=\"%s\"", field_name); |
4f45f9bb JD |
380 | goto error; |
381 | } | |
382 | BT_PUT(field_type); | |
383 | ||
384 | seq_len = bt_ctf_field_sequence_get_length(field); | |
b4d4912f | 385 | assert(seq_len); |
4f45f9bb JD |
386 | |
387 | ret = bt_ctf_field_unsigned_integer_get_value(seq_len, build_id_len); | |
388 | if (ret) { | |
b4d4912f JD |
389 | BT_LOGE("Failed to get value: field-name=\"%s\"", |
390 | field_name); | |
4f45f9bb JD |
391 | goto error; |
392 | } | |
393 | BT_PUT(seq_len); | |
394 | ||
395 | *build_id = g_new0(uint8_t, *build_id_len); | |
396 | if (!*build_id) { | |
b4d4912f | 397 | BT_LOGE_STR("Failed to allocate build_id."); |
4f45f9bb JD |
398 | goto error; |
399 | } | |
400 | ||
401 | for (i = 0; i < *build_id_len; i++) { | |
402 | uint64_t tmp; | |
403 | ||
404 | seq_field = bt_ctf_field_sequence_get_field(field, i); | |
405 | if (!seq_field) { | |
b4d4912f JD |
406 | BT_LOGE("Failed to get field in sequence: sequence-name=\"%s\", index=%" PRIu64, |
407 | field_name, i); | |
4f45f9bb JD |
408 | goto error; |
409 | } | |
410 | ||
411 | ret = bt_ctf_field_unsigned_integer_get_value(seq_field, &tmp); | |
412 | if (ret) { | |
b4d4912f JD |
413 | BT_LOGE("Failed to get value: field-name=\"%s\"", |
414 | field_name); | |
4f45f9bb JD |
415 | goto error; |
416 | } | |
b4d4912f | 417 | |
4f45f9bb JD |
418 | BT_PUT(seq_field); |
419 | (*build_id)[i] = (uint8_t) tmp; | |
420 | } | |
421 | ret = 0; | |
422 | goto end; | |
423 | ||
424 | error: | |
425 | g_free(*build_id); | |
426 | ret = -1; | |
427 | end: | |
428 | bt_put(field_type); | |
429 | bt_put(field); | |
430 | return ret; | |
431 | } | |
432 | ||
433 | static | |
434 | struct debug_info *lookup_trace_debug_info(struct debug_info_iterator *debug_it, | |
504db471 JD |
435 | struct bt_ctf_trace *writer_trace, |
436 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
437 | { |
438 | return (struct debug_info *) g_hash_table_lookup( | |
504db471 | 439 | di_trace->trace_debug_map, |
4f45f9bb JD |
440 | (gpointer) writer_trace); |
441 | } | |
442 | ||
443 | static | |
444 | struct debug_info *insert_new_debug_info(struct debug_info_iterator *debug_it, | |
504db471 JD |
445 | struct bt_ctf_trace *writer_trace, |
446 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
447 | { |
448 | struct debug_info *debug_info = NULL; | |
449 | struct bt_value *field = NULL; | |
450 | const char *str_value; | |
451 | enum bt_value_status ret; | |
452 | ||
453 | field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, | |
454 | "domain"); | |
455 | /* No domain field, no debug info */ | |
456 | if (!field) { | |
457 | goto end; | |
458 | } | |
459 | ret = bt_value_string_get(field, &str_value); | |
b4d4912f JD |
460 | assert(ret == BT_VALUE_STATUS_OK); |
461 | ||
4f45f9bb JD |
462 | /* Domain not ust, no debug info */ |
463 | if (strcmp(str_value, "ust") != 0) { | |
464 | goto end; | |
465 | } | |
466 | BT_PUT(field); | |
467 | ||
468 | /* No tracer_name, no debug info */ | |
469 | field = bt_ctf_trace_get_environment_field_value_by_name(writer_trace, | |
470 | "tracer_name"); | |
471 | /* No tracer_name, no debug info */ | |
472 | if (!field) { | |
473 | goto end; | |
474 | } | |
475 | ret = bt_value_string_get(field, &str_value); | |
b4d4912f JD |
476 | assert(ret == BT_VALUE_STATUS_OK); |
477 | ||
4f45f9bb JD |
478 | /* Tracer_name not lttng-ust, no debug info */ |
479 | if (strcmp(str_value, "lttng-ust") != 0) { | |
480 | goto end; | |
481 | } | |
482 | BT_PUT(field); | |
483 | ||
9d325e17 | 484 | debug_info = debug_info_create(debug_it->debug_info_component); |
4f45f9bb | 485 | if (!debug_info) { |
b4d4912f | 486 | BT_LOGE_STR("Failed to create debug info."); |
4f45f9bb JD |
487 | goto end; |
488 | } | |
489 | ||
504db471 | 490 | g_hash_table_insert(di_trace->trace_debug_map, (gpointer) writer_trace, |
4f45f9bb JD |
491 | debug_info); |
492 | ||
493 | end: | |
494 | bt_put(field); | |
495 | return debug_info; | |
496 | } | |
497 | ||
498 | static | |
499 | struct debug_info *get_trace_debug_info(struct debug_info_iterator *debug_it, | |
504db471 JD |
500 | struct bt_ctf_trace *writer_trace, |
501 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
502 | { |
503 | struct debug_info *debug_info; | |
504 | ||
504db471 | 505 | debug_info = lookup_trace_debug_info(debug_it, writer_trace, di_trace); |
4f45f9bb JD |
506 | if (debug_info) { |
507 | goto end; | |
508 | } | |
509 | ||
504db471 | 510 | debug_info = insert_new_debug_info(debug_it, writer_trace, di_trace); |
4f45f9bb JD |
511 | |
512 | end: | |
513 | return debug_info; | |
514 | } | |
515 | ||
516 | static | |
504db471 | 517 | struct debug_info_trace *lookup_trace(struct debug_info_iterator *debug_it, |
4f45f9bb JD |
518 | struct bt_ctf_trace *trace) |
519 | { | |
504db471 | 520 | return (struct debug_info_trace *) g_hash_table_lookup( |
4f45f9bb JD |
521 | debug_it->trace_map, |
522 | (gpointer) trace); | |
523 | } | |
524 | ||
1c78e839 JD |
525 | static |
526 | enum debug_info_stream_state *insert_new_stream_state( | |
527 | struct debug_info_iterator *debug_it, | |
528 | struct debug_info_trace *di_trace, struct bt_ctf_stream *stream) | |
529 | { | |
530 | enum debug_info_stream_state *v = NULL; | |
531 | ||
532 | v = g_new0(enum debug_info_stream_state, 1); | |
533 | if (!v) { | |
b4d4912f | 534 | BT_LOGE_STR("Failed to allocate debug_info_stream_state."); |
ec273a88 | 535 | goto end; |
1c78e839 JD |
536 | } |
537 | *v = DEBUG_INFO_UNKNOWN_STREAM; | |
538 | ||
539 | g_hash_table_insert(di_trace->stream_states, stream, v); | |
540 | ||
ec273a88 | 541 | end: |
1c78e839 JD |
542 | return v; |
543 | } | |
544 | ||
545 | static | |
546 | void check_completed_trace(gpointer key, gpointer value, gpointer user_data) | |
547 | { | |
548 | enum debug_info_stream_state *state = value; | |
549 | int *trace_completed = user_data; | |
550 | ||
551 | if (*state != DEBUG_INFO_COMPLETED_STREAM) { | |
552 | *trace_completed = 0; | |
553 | } | |
554 | } | |
555 | ||
556 | static | |
557 | gboolean empty_ht(gpointer key, gpointer value, gpointer user_data) | |
558 | { | |
559 | return TRUE; | |
560 | } | |
561 | ||
562 | BT_HIDDEN | |
563 | void debug_info_close_trace(struct debug_info_iterator *debug_it, | |
564 | struct debug_info_trace *di_trace) | |
565 | { | |
ec273a88 | 566 | if (di_trace->static_listener_id >= 0) { |
1c78e839 JD |
567 | bt_ctf_trace_remove_is_static_listener(di_trace->trace, |
568 | di_trace->static_listener_id); | |
569 | } | |
570 | ||
571 | /* Empty the stream class HT. */ | |
572 | g_hash_table_foreach_remove(di_trace->stream_class_map, | |
573 | empty_ht, NULL); | |
574 | g_hash_table_destroy(di_trace->stream_class_map); | |
575 | ||
576 | /* Empty the stream HT. */ | |
577 | g_hash_table_foreach_remove(di_trace->stream_map, | |
578 | empty_ht, NULL); | |
579 | g_hash_table_destroy(di_trace->stream_map); | |
580 | ||
581 | /* Empty the stream state HT. */ | |
582 | g_hash_table_foreach_remove(di_trace->stream_states, | |
583 | empty_ht, NULL); | |
584 | g_hash_table_destroy(di_trace->stream_states); | |
585 | ||
586 | /* Empty the packet HT. */ | |
587 | g_hash_table_foreach_remove(di_trace->packet_map, | |
588 | empty_ht, NULL); | |
589 | g_hash_table_destroy(di_trace->packet_map); | |
590 | ||
591 | /* Empty the trace_debug HT. */ | |
592 | g_hash_table_foreach_remove(di_trace->trace_debug_map, | |
593 | empty_ht, NULL); | |
594 | g_hash_table_destroy(di_trace->trace_debug_map); | |
595 | } | |
596 | ||
cb0a5cf8 JD |
597 | static |
598 | int sync_event_classes(struct debug_info_iterator *debug_it, | |
599 | struct bt_ctf_stream *stream, | |
600 | struct bt_ctf_stream *writer_stream) | |
601 | { | |
602 | int int_ret; | |
603 | struct bt_ctf_stream_class *stream_class = NULL, | |
604 | *writer_stream_class = NULL; | |
605 | enum bt_component_status ret; | |
606 | ||
607 | stream_class = bt_ctf_stream_get_class(stream); | |
b4d4912f | 608 | assert(stream_class); |
cb0a5cf8 JD |
609 | |
610 | writer_stream_class = bt_ctf_stream_get_class(writer_stream); | |
b4d4912f | 611 | assert(writer_stream_class); |
cb0a5cf8 JD |
612 | |
613 | ret = ctf_copy_event_classes(debug_it->err, stream_class, | |
614 | writer_stream_class); | |
615 | if (ret != BT_COMPONENT_STATUS_OK) { | |
b4d4912f | 616 | BT_LOGE_STR("Failed to copy event classes."); |
cb0a5cf8 JD |
617 | goto error; |
618 | } | |
619 | ||
620 | int_ret = 0; | |
621 | goto end; | |
622 | ||
623 | error: | |
624 | int_ret = -1; | |
625 | end: | |
626 | bt_put(stream_class); | |
627 | bt_put(writer_stream_class); | |
628 | return int_ret; | |
629 | } | |
630 | ||
1c78e839 JD |
631 | static |
632 | void trace_is_static_listener(struct bt_ctf_trace *trace, void *data) | |
633 | { | |
634 | struct debug_info_trace *di_trace = data; | |
cb0a5cf8 JD |
635 | int trace_completed = 1, ret, nr_stream, i; |
636 | struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; | |
637 | struct bt_ctf_trace *writer_trace = di_trace->writer_trace; | |
638 | ||
639 | /* | |
640 | * When the trace becomes static, make sure that we have all | |
641 | * the event classes in our stream_class copies before setting it | |
642 | * static as well. | |
643 | */ | |
644 | nr_stream = bt_ctf_trace_get_stream_count(trace); | |
645 | for (i = 0; i < nr_stream; i++) { | |
646 | stream = bt_ctf_trace_get_stream_by_index(trace, i); | |
b4d4912f JD |
647 | assert(stream); |
648 | ||
cb0a5cf8 | 649 | writer_stream = bt_ctf_trace_get_stream_by_index(writer_trace, i); |
b4d4912f JD |
650 | assert(writer_stream); |
651 | ||
cb0a5cf8 JD |
652 | ret = sync_event_classes(di_trace->debug_it, stream, writer_stream); |
653 | if (ret) { | |
b4d4912f | 654 | BT_LOGE_STR("Failed to synchronize the event classes."); |
cb0a5cf8 JD |
655 | goto error; |
656 | } | |
657 | BT_PUT(stream); | |
658 | BT_PUT(writer_stream); | |
659 | } | |
1c78e839 | 660 | |
cb0a5cf8 | 661 | bt_ctf_trace_set_is_static(di_trace->writer_trace); |
1c78e839 JD |
662 | di_trace->trace_static = 1; |
663 | ||
664 | g_hash_table_foreach(di_trace->stream_states, | |
665 | check_completed_trace, &trace_completed); | |
666 | if (trace_completed) { | |
667 | debug_info_close_trace(di_trace->debug_it, di_trace); | |
668 | g_hash_table_remove(di_trace->debug_it->trace_map, | |
669 | di_trace->trace); | |
670 | } | |
cb0a5cf8 JD |
671 | |
672 | error: | |
673 | bt_put(writer_stream); | |
674 | bt_put(stream); | |
1c78e839 JD |
675 | } |
676 | ||
4f45f9bb | 677 | static |
504db471 JD |
678 | struct debug_info_trace *insert_new_trace(struct debug_info_iterator *debug_it, |
679 | struct bt_ctf_stream *stream) { | |
4f45f9bb | 680 | struct bt_ctf_trace *writer_trace = NULL; |
504db471 JD |
681 | struct debug_info_trace *di_trace = NULL; |
682 | struct bt_ctf_trace *trace = NULL; | |
683 | struct bt_ctf_stream_class *stream_class = NULL; | |
cb0a5cf8 | 684 | struct bt_ctf_stream *writer_stream = NULL; |
1c78e839 | 685 | int ret, nr_stream, i; |
4f45f9bb JD |
686 | |
687 | writer_trace = bt_ctf_trace_create(); | |
688 | if (!writer_trace) { | |
b4d4912f | 689 | BT_LOGE_STR("Failed to create a new trace."); |
4f45f9bb JD |
690 | goto error; |
691 | } | |
504db471 JD |
692 | |
693 | stream_class = bt_ctf_stream_get_class(stream); | |
b4d4912f | 694 | assert(stream_class); |
504db471 JD |
695 | |
696 | trace = bt_ctf_stream_class_get_trace(stream_class); | |
b4d4912f | 697 | assert(trace); |
4f45f9bb JD |
698 | |
699 | ret = ctf_copy_trace(debug_it->err, trace, writer_trace); | |
700 | if (ret != BT_COMPONENT_STATUS_OK) { | |
b4d4912f | 701 | BT_LOGE_STR("Failed to copy CTF trace."); |
4f45f9bb JD |
702 | goto error; |
703 | } | |
704 | ||
504db471 JD |
705 | di_trace = g_new0(struct debug_info_trace, 1); |
706 | if (!di_trace) { | |
b4d4912f | 707 | BT_LOGE_STR("Failed to allocate debug_info_trace."); |
504db471 JD |
708 | goto error; |
709 | } | |
710 | ||
711 | di_trace->trace = trace; | |
712 | di_trace->writer_trace = writer_trace; | |
713 | di_trace->debug_info_component = debug_it->debug_info_component; | |
1c78e839 | 714 | di_trace->debug_it = debug_it; |
504db471 JD |
715 | di_trace->stream_map = g_hash_table_new_full(g_direct_hash, |
716 | g_direct_equal, NULL, (GDestroyNotify) unref_stream); | |
717 | di_trace->stream_class_map = g_hash_table_new_full(g_direct_hash, | |
718 | g_direct_equal, NULL, (GDestroyNotify) unref_stream_class); | |
719 | di_trace->packet_map = g_hash_table_new_full(g_direct_hash, | |
720 | g_direct_equal, NULL, (GDestroyNotify) unref_packet); | |
721 | di_trace->trace_debug_map = g_hash_table_new_full(g_direct_hash, | |
722 | g_direct_equal, NULL, (GDestroyNotify) unref_debug_info); | |
1c78e839 JD |
723 | di_trace->stream_states = g_hash_table_new_full(g_direct_hash, |
724 | g_direct_equal, NULL, destroy_stream_state_key); | |
cb0a5cf8 | 725 | g_hash_table_insert(debug_it->trace_map, (gpointer) trace, di_trace); |
1c78e839 JD |
726 | |
727 | /* Set all the existing streams in the unknown state. */ | |
728 | nr_stream = bt_ctf_trace_get_stream_count(trace); | |
729 | for (i = 0; i < nr_stream; i++) { | |
730 | stream = bt_ctf_trace_get_stream_by_index(trace, i); | |
b4d4912f JD |
731 | assert(stream); |
732 | ||
1c78e839 | 733 | insert_new_stream_state(debug_it, di_trace, stream); |
cb0a5cf8 JD |
734 | writer_stream = insert_new_stream(debug_it, stream, di_trace); |
735 | if (!writer_stream) { | |
b4d4912f | 736 | BT_LOGE_STR("Failed to insert new stream."); |
cb0a5cf8 JD |
737 | goto error; |
738 | } | |
739 | bt_get(writer_stream); | |
740 | ret = sync_event_classes(debug_it, stream, writer_stream); | |
741 | if (ret) { | |
b4d4912f | 742 | BT_LOGE_STR("Failed to synchronize event classes."); |
cb0a5cf8 JD |
743 | goto error; |
744 | } | |
745 | BT_PUT(writer_stream); | |
1c78e839 JD |
746 | BT_PUT(stream); |
747 | } | |
748 | ||
749 | /* Check if the trace is already static or register a listener. */ | |
750 | if (bt_ctf_trace_is_static(trace)) { | |
751 | di_trace->trace_static = 1; | |
752 | di_trace->static_listener_id = -1; | |
cb0a5cf8 | 753 | bt_ctf_trace_set_is_static(writer_trace); |
1c78e839 JD |
754 | } else { |
755 | ret = bt_ctf_trace_add_is_static_listener(trace, | |
756 | trace_is_static_listener, di_trace); | |
b4d4912f | 757 | assert(ret >= 0); |
1c78e839 JD |
758 | di_trace->static_listener_id = ret; |
759 | } | |
504db471 | 760 | |
504db471 | 761 | |
4f45f9bb JD |
762 | goto end; |
763 | ||
764 | error: | |
765 | BT_PUT(writer_trace); | |
504db471 JD |
766 | g_free(di_trace); |
767 | di_trace = NULL; | |
4f45f9bb | 768 | end: |
cb0a5cf8 JD |
769 | bt_put(stream); |
770 | bt_put(writer_stream); | |
504db471 JD |
771 | bt_put(stream_class); |
772 | bt_put(trace); | |
773 | return di_trace; | |
4f45f9bb JD |
774 | } |
775 | ||
776 | static | |
777 | struct bt_ctf_packet *lookup_packet(struct debug_info_iterator *debug_it, | |
504db471 JD |
778 | struct bt_ctf_packet *packet, |
779 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
780 | { |
781 | return (struct bt_ctf_packet *) g_hash_table_lookup( | |
504db471 | 782 | di_trace->packet_map, |
4f45f9bb JD |
783 | (gpointer) packet); |
784 | } | |
785 | ||
786 | static | |
787 | struct bt_ctf_packet *insert_new_packet(struct debug_info_iterator *debug_it, | |
788 | struct bt_ctf_packet *packet, | |
504db471 JD |
789 | struct bt_ctf_stream *writer_stream, |
790 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
791 | { |
792 | struct bt_ctf_packet *writer_packet; | |
387483fc | 793 | int ret; |
4f45f9bb JD |
794 | |
795 | writer_packet = bt_ctf_packet_create(writer_stream); | |
796 | if (!writer_packet) { | |
b4d4912f | 797 | BT_LOGE_STR("Failed to create new packet."); |
387483fc JD |
798 | goto error; |
799 | } | |
800 | ||
801 | ret = ctf_packet_copy_header(debug_it->err, packet, writer_packet); | |
802 | if (ret) { | |
b4d4912f | 803 | BT_LOGE_STR("Failed to copy packet header."); |
387483fc | 804 | goto error; |
4f45f9bb | 805 | } |
4f45f9bb | 806 | |
387483fc JD |
807 | g_hash_table_insert(di_trace->packet_map, (gpointer) packet, |
808 | writer_packet); | |
809 | goto end; | |
810 | ||
811 | error: | |
812 | BT_PUT(writer_packet); | |
4f45f9bb JD |
813 | end: |
814 | return writer_packet; | |
815 | } | |
816 | ||
817 | static | |
818 | int add_debug_info_fields(FILE *err, | |
819 | struct bt_ctf_field_type *writer_event_context_type, | |
820 | struct debug_info_component *component) | |
821 | { | |
822 | struct bt_ctf_field_type *ip_field = NULL, *debug_field_type = NULL, | |
823 | *bin_field_type = NULL, *func_field_type = NULL, | |
824 | *src_field_type = NULL; | |
825 | int ret = 0; | |
826 | ||
827 | ip_field = bt_ctf_field_type_structure_get_field_type_by_name( | |
828 | writer_event_context_type, "_ip"); | |
829 | /* No ip field, so no debug info. */ | |
830 | if (!ip_field) { | |
831 | goto end; | |
832 | } | |
833 | BT_PUT(ip_field); | |
834 | ||
835 | debug_field_type = bt_ctf_field_type_structure_get_field_type_by_name( | |
836 | writer_event_context_type, | |
837 | component->arg_debug_info_field_name); | |
838 | /* Already existing debug_info field, no need to add it. */ | |
839 | if (debug_field_type) { | |
840 | goto end; | |
841 | } | |
842 | ||
843 | debug_field_type = bt_ctf_field_type_structure_create(); | |
844 | if (!debug_field_type) { | |
b4d4912f | 845 | BT_LOGE_STR("Failed to create debug_info structure."); |
4f45f9bb JD |
846 | goto error; |
847 | } | |
848 | ||
849 | bin_field_type = bt_ctf_field_type_string_create(); | |
850 | if (!bin_field_type) { | |
b4d4912f | 851 | BT_LOGE_STR("Failed to create string for field=bin."); |
4f45f9bb JD |
852 | goto error; |
853 | } | |
854 | ||
855 | func_field_type = bt_ctf_field_type_string_create(); | |
856 | if (!func_field_type) { | |
b4d4912f | 857 | BT_LOGE_STR("Failed to create string for field=func."); |
4f45f9bb JD |
858 | goto error; |
859 | } | |
860 | ||
861 | src_field_type = bt_ctf_field_type_string_create(); | |
862 | if (!src_field_type) { | |
b4d4912f | 863 | BT_LOGE_STR("Failed to create string for field=src."); |
4f45f9bb JD |
864 | goto error; |
865 | } | |
866 | ||
867 | ret = bt_ctf_field_type_structure_add_field(debug_field_type, | |
868 | bin_field_type, "bin"); | |
869 | if (ret) { | |
b4d4912f | 870 | BT_LOGE_STR("Failed to add a field to debug_info struct: field=bin."); |
4f45f9bb JD |
871 | goto error; |
872 | } | |
873 | ||
874 | ret = bt_ctf_field_type_structure_add_field(debug_field_type, | |
875 | func_field_type, "func"); | |
876 | if (ret) { | |
b4d4912f | 877 | BT_LOGE_STR("Failed to add a field to debug_info struct: field=func."); |
4f45f9bb JD |
878 | goto error; |
879 | } | |
880 | ||
881 | ret = bt_ctf_field_type_structure_add_field(debug_field_type, | |
882 | src_field_type, "src"); | |
883 | if (ret) { | |
b4d4912f | 884 | BT_LOGE_STR("Failed to add a field to debug_info struct: field=src."); |
4f45f9bb JD |
885 | goto error; |
886 | } | |
887 | ||
888 | ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, | |
889 | debug_field_type, component->arg_debug_info_field_name); | |
890 | if (ret) { | |
b4d4912f | 891 | BT_LOGE_STR("Failed to add debug_info field to event_context."); |
4f45f9bb JD |
892 | goto error; |
893 | } | |
894 | ||
895 | ret = 0; | |
896 | goto end; | |
897 | ||
898 | error: | |
899 | BT_PUT(debug_field_type); | |
900 | ret = -1; | |
901 | end: | |
902 | bt_put(src_field_type); | |
903 | bt_put(func_field_type); | |
904 | bt_put(bin_field_type); | |
905 | bt_put(debug_field_type); | |
906 | return ret; | |
907 | } | |
908 | ||
909 | static | |
910 | int create_debug_info_event_context_type(FILE *err, | |
911 | struct bt_ctf_field_type *event_context_type, | |
912 | struct bt_ctf_field_type *writer_event_context_type, | |
913 | struct debug_info_component *component) | |
914 | { | |
915 | int ret, nr_fields, i; | |
916 | ||
917 | nr_fields = bt_ctf_field_type_structure_get_field_count(event_context_type); | |
918 | for (i = 0; i < nr_fields; i++) { | |
919 | struct bt_ctf_field_type *field_type = NULL; | |
920 | const char *field_name; | |
921 | ||
922 | if (bt_ctf_field_type_structure_get_field(event_context_type, | |
923 | &field_name, &field_type, i) < 0) { | |
b4d4912f JD |
924 | BT_LOGE("Failed to get a field from the event-context: field-name=\"%s\"", |
925 | field_name); | |
4f45f9bb JD |
926 | goto error; |
927 | } | |
928 | ||
929 | ret = bt_ctf_field_type_structure_add_field(writer_event_context_type, | |
930 | field_type, field_name); | |
931 | BT_PUT(field_type); | |
932 | if (ret) { | |
b4d4912f JD |
933 | BT_LOGE("Failed to add a field to the event-context: field-name=\"%s\"", |
934 | field_name); | |
4f45f9bb JD |
935 | goto error; |
936 | } | |
937 | } | |
938 | ||
939 | ret = add_debug_info_fields(err, writer_event_context_type, | |
940 | component); | |
941 | goto end; | |
942 | ||
943 | error: | |
944 | ret = -1; | |
945 | end: | |
946 | return ret; | |
947 | } | |
948 | ||
949 | static | |
950 | struct bt_ctf_stream_class *copy_stream_class_debug_info(FILE *err, | |
951 | struct bt_ctf_stream_class *stream_class, | |
952 | struct bt_ctf_trace *writer_trace, | |
953 | struct debug_info_component *component) | |
954 | { | |
955 | struct bt_ctf_field_type *type = NULL; | |
956 | struct bt_ctf_stream_class *writer_stream_class = NULL; | |
957 | struct bt_ctf_field_type *writer_event_context_type = NULL; | |
958 | int ret_int; | |
959 | const char *name = bt_ctf_stream_class_get_name(stream_class); | |
960 | ||
2d64a1eb | 961 | writer_stream_class = bt_ctf_stream_class_create_empty(name); |
4f45f9bb | 962 | if (!writer_stream_class) { |
b4d4912f | 963 | BT_LOGE_STR("Failed to create empty stream class."); |
4f45f9bb JD |
964 | goto error; |
965 | } | |
966 | ||
967 | type = bt_ctf_stream_class_get_packet_context_type(stream_class); | |
2d64a1eb JD |
968 | if (type) { |
969 | ret_int = bt_ctf_stream_class_set_packet_context_type( | |
970 | writer_stream_class, type); | |
971 | if (ret_int < 0) { | |
b4d4912f | 972 | BT_LOGE_STR("Failed to set packet_context type."); |
2d64a1eb JD |
973 | goto error; |
974 | } | |
975 | BT_PUT(type); | |
4f45f9bb | 976 | } |
4f45f9bb JD |
977 | |
978 | type = bt_ctf_stream_class_get_event_header_type(stream_class); | |
290b95cc MD |
979 | if (type) { |
980 | ret_int = bt_ctf_stream_class_set_event_header_type( | |
981 | writer_stream_class, type); | |
982 | if (ret_int < 0) { | |
b4d4912f | 983 | BT_LOGE_STR("Failed to set event_header type."); |
290b95cc MD |
984 | goto error; |
985 | } | |
986 | BT_PUT(type); | |
4f45f9bb | 987 | } |
4f45f9bb JD |
988 | |
989 | type = bt_ctf_stream_class_get_event_context_type(stream_class); | |
990 | if (type) { | |
991 | writer_event_context_type = bt_ctf_field_type_structure_create(); | |
992 | if (!writer_event_context_type) { | |
b4d4912f | 993 | BT_LOGE_STR("Failed to create writer_event_context struct type."); |
4f45f9bb JD |
994 | goto error; |
995 | } | |
996 | ret_int = create_debug_info_event_context_type(err, type, | |
997 | writer_event_context_type, component); | |
998 | if (ret_int) { | |
b4d4912f | 999 | BT_LOGE_STR("Failed to create debug_info event_context type."); |
4f45f9bb JD |
1000 | goto error; |
1001 | } | |
1002 | BT_PUT(type); | |
1003 | ||
1004 | ret_int = bt_ctf_stream_class_set_event_context_type( | |
1005 | writer_stream_class, writer_event_context_type); | |
1006 | if (ret_int < 0) { | |
b4d4912f | 1007 | BT_LOGE_STR("Failed to set event_context type."); |
4f45f9bb JD |
1008 | goto error; |
1009 | } | |
1010 | BT_PUT(writer_event_context_type); | |
1011 | } | |
1012 | ||
1013 | goto end; | |
1014 | ||
1015 | error: | |
1016 | BT_PUT(writer_stream_class); | |
1017 | end: | |
1018 | bt_put(writer_event_context_type); | |
1019 | bt_put(type); | |
1020 | return writer_stream_class; | |
1021 | } | |
1022 | ||
1023 | /* | |
1024 | * Add the original clock classes to the new trace, we do not need to copy | |
1025 | * them, and if we did, we would have to manually inspect the stream class | |
1026 | * to update the integers mapping to a clock. | |
1027 | */ | |
1028 | static | |
1029 | int add_clock_classes(FILE *err, struct bt_ctf_trace *writer_trace, | |
1030 | struct bt_ctf_stream_class *writer_stream_class, | |
1031 | struct bt_ctf_trace *trace) | |
1032 | { | |
1033 | int ret, clock_class_count, i; | |
1034 | ||
1035 | clock_class_count = bt_ctf_trace_get_clock_class_count(trace); | |
1036 | ||
1037 | for (i = 0; i < clock_class_count; i++) { | |
1038 | struct bt_ctf_clock_class *clock_class = | |
9ac68eb1 | 1039 | bt_ctf_trace_get_clock_class_by_index(trace, i); |
30480ffe | 1040 | struct bt_ctf_clock_class *existing_clock_class = NULL; |
4f45f9bb | 1041 | |
b4d4912f | 1042 | assert(clock_class); |
4f45f9bb | 1043 | |
30480ffe PP |
1044 | existing_clock_class = bt_ctf_trace_get_clock_class_by_name( |
1045 | writer_trace, bt_ctf_clock_class_get_name(clock_class)); | |
1046 | bt_put(existing_clock_class); | |
1047 | if (existing_clock_class) { | |
1048 | bt_put(clock_class); | |
1049 | continue; | |
1050 | } | |
1051 | ||
4f45f9bb JD |
1052 | ret = bt_ctf_trace_add_clock_class(writer_trace, clock_class); |
1053 | BT_PUT(clock_class); | |
1054 | if (ret != 0) { | |
b4d4912f | 1055 | BT_LOGE_STR("Failed to add clock_class."); |
4f45f9bb JD |
1056 | goto error; |
1057 | } | |
1058 | } | |
1059 | ||
1060 | ret = 0; | |
1061 | goto end; | |
1062 | ||
1063 | error: | |
1064 | ret = -1; | |
1065 | end: | |
1066 | return ret; | |
1067 | ||
1068 | } | |
1069 | ||
1070 | static | |
1071 | struct bt_ctf_stream_class *insert_new_stream_class( | |
1072 | struct debug_info_iterator *debug_it, | |
1073 | struct bt_ctf_stream_class *stream_class) | |
1074 | { | |
1075 | struct bt_ctf_stream_class *writer_stream_class = NULL; | |
1076 | struct bt_ctf_trace *trace, *writer_trace = NULL; | |
504db471 | 1077 | struct debug_info_trace *di_trace; |
4f45f9bb JD |
1078 | enum bt_component_status ret; |
1079 | int int_ret; | |
1080 | ||
1081 | trace = bt_ctf_stream_class_get_trace(stream_class); | |
b4d4912f | 1082 | assert(trace); |
4f45f9bb | 1083 | |
504db471 JD |
1084 | di_trace = lookup_trace(debug_it, trace); |
1085 | if (!di_trace) { | |
b4d4912f | 1086 | BT_LOGE_STR("Failed to find existing trace."); |
504db471 JD |
1087 | ret = BT_COMPONENT_STATUS_ERROR; |
1088 | goto error; | |
4f45f9bb | 1089 | } |
504db471 | 1090 | writer_trace = di_trace->writer_trace; |
4f45f9bb JD |
1091 | bt_get(writer_trace); |
1092 | ||
1093 | writer_stream_class = copy_stream_class_debug_info(debug_it->err, stream_class, | |
1094 | writer_trace, debug_it->debug_info_component); | |
1095 | if (!writer_stream_class) { | |
b4d4912f | 1096 | BT_LOGE_STR("Failed to copy stream class."); |
4f45f9bb JD |
1097 | goto error; |
1098 | } | |
1099 | ||
1100 | int_ret = bt_ctf_trace_add_stream_class(writer_trace, writer_stream_class); | |
1101 | if (int_ret) { | |
b4d4912f | 1102 | BT_LOGE_STR("Failed to add stream class."); |
4f45f9bb JD |
1103 | goto error; |
1104 | } | |
1105 | ||
1106 | ret = add_clock_classes(debug_it->err, writer_trace, | |
1107 | writer_stream_class, trace); | |
1108 | if (ret != BT_COMPONENT_STATUS_OK) { | |
b4d4912f | 1109 | BT_LOGE_STR("Failed to add clock classes."); |
4f45f9bb JD |
1110 | goto error; |
1111 | } | |
4f45f9bb | 1112 | |
504db471 | 1113 | g_hash_table_insert(di_trace->stream_class_map, |
4f45f9bb JD |
1114 | (gpointer) stream_class, writer_stream_class); |
1115 | ||
1116 | goto end; | |
1117 | ||
1118 | error: | |
1119 | BT_PUT(writer_stream_class); | |
1120 | end: | |
1121 | bt_put(trace); | |
1122 | bt_put(writer_trace); | |
1123 | return writer_stream_class; | |
1124 | } | |
1125 | ||
1126 | static | |
1127 | struct bt_ctf_stream *insert_new_stream( | |
1128 | struct debug_info_iterator *debug_it, | |
504db471 JD |
1129 | struct bt_ctf_stream *stream, |
1130 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
1131 | { |
1132 | struct bt_ctf_stream *writer_stream = NULL; | |
504db471 | 1133 | struct bt_ctf_stream_class *stream_class = NULL; |
4f45f9bb | 1134 | struct bt_ctf_stream_class *writer_stream_class = NULL; |
b910013b | 1135 | int64_t id; |
4f45f9bb | 1136 | |
504db471 | 1137 | stream_class = bt_ctf_stream_get_class(stream); |
b4d4912f | 1138 | assert(stream_class); |
504db471 | 1139 | |
4f45f9bb | 1140 | writer_stream_class = g_hash_table_lookup( |
504db471 | 1141 | di_trace->stream_class_map, |
4f45f9bb JD |
1142 | (gpointer) stream_class); |
1143 | ||
1144 | if (!writer_stream_class) { | |
1145 | writer_stream_class = insert_new_stream_class(debug_it, | |
1146 | stream_class); | |
1147 | if (!writer_stream_class) { | |
b4d4912f | 1148 | BT_LOGE_STR("Failed to insert new stream class."); |
4f45f9bb JD |
1149 | goto error; |
1150 | } | |
1151 | } | |
1152 | bt_get(writer_stream_class); | |
1153 | ||
b910013b PP |
1154 | id = bt_ctf_stream_get_id(stream); |
1155 | if (id < 0) { | |
1156 | writer_stream = bt_ctf_stream_create(writer_stream_class, | |
1157 | bt_ctf_stream_get_name(stream)); | |
1158 | } else { | |
1159 | writer_stream = bt_ctf_stream_create_with_id( | |
1160 | writer_stream_class, | |
1161 | bt_ctf_stream_get_name(stream), id); | |
1162 | } | |
1163 | ||
4f45f9bb | 1164 | if (!writer_stream) { |
b4d4912f | 1165 | BT_LOGE_STR("Failed to create writer_stream."); |
4f45f9bb JD |
1166 | goto error; |
1167 | } | |
1168 | ||
504db471 | 1169 | g_hash_table_insert(di_trace->stream_map, (gpointer) stream, |
4f45f9bb JD |
1170 | writer_stream); |
1171 | ||
1172 | goto end; | |
1173 | ||
1174 | error: | |
1175 | BT_PUT(writer_stream); | |
1176 | end: | |
504db471 | 1177 | bt_put(stream_class); |
4f45f9bb JD |
1178 | bt_put(writer_stream_class); |
1179 | return writer_stream; | |
1180 | } | |
1181 | ||
1182 | static | |
1183 | struct bt_ctf_stream *lookup_stream(struct debug_info_iterator *debug_it, | |
504db471 JD |
1184 | struct bt_ctf_stream *stream, |
1185 | struct debug_info_trace *di_trace) | |
4f45f9bb JD |
1186 | { |
1187 | return (struct bt_ctf_stream *) g_hash_table_lookup( | |
504db471 | 1188 | di_trace->stream_map, (gpointer) stream); |
4f45f9bb JD |
1189 | } |
1190 | ||
1191 | static | |
1192 | struct bt_ctf_event_class *get_event_class(struct debug_info_iterator *debug_it, | |
1193 | struct bt_ctf_stream_class *writer_stream_class, | |
1194 | struct bt_ctf_event_class *event_class) | |
1195 | { | |
a9f0d01b PP |
1196 | return bt_ctf_stream_class_get_event_class_by_id(writer_stream_class, |
1197 | bt_ctf_event_class_get_id(event_class)); | |
4f45f9bb JD |
1198 | } |
1199 | ||
504db471 JD |
1200 | static |
1201 | struct debug_info_trace *lookup_di_trace_from_stream( | |
1202 | struct debug_info_iterator *debug_it, | |
1203 | struct bt_ctf_stream *stream) | |
1204 | { | |
1205 | struct bt_ctf_stream_class *stream_class = NULL; | |
1206 | struct bt_ctf_trace *trace = NULL; | |
1207 | struct debug_info_trace *di_trace = NULL; | |
1208 | ||
1209 | stream_class = bt_ctf_stream_get_class(stream); | |
b4d4912f | 1210 | assert(stream_class); |
504db471 JD |
1211 | |
1212 | trace = bt_ctf_stream_class_get_trace(stream_class); | |
b4d4912f | 1213 | assert(trace); |
504db471 JD |
1214 | |
1215 | di_trace = (struct debug_info_trace *) g_hash_table_lookup( | |
1216 | debug_it->trace_map, (gpointer) trace); | |
1217 | ||
504db471 JD |
1218 | BT_PUT(stream_class); |
1219 | BT_PUT(trace); | |
1220 | return di_trace; | |
1221 | } | |
1222 | ||
4f45f9bb JD |
1223 | static |
1224 | struct bt_ctf_stream *get_writer_stream( | |
1225 | struct debug_info_iterator *debug_it, | |
1226 | struct bt_ctf_packet *packet, struct bt_ctf_stream *stream) | |
1227 | { | |
1228 | struct bt_ctf_stream_class *stream_class = NULL; | |
1229 | struct bt_ctf_stream *writer_stream = NULL; | |
504db471 | 1230 | struct debug_info_trace *di_trace = NULL; |
4f45f9bb JD |
1231 | |
1232 | stream_class = bt_ctf_stream_get_class(stream); | |
b4d4912f | 1233 | assert(stream_class); |
4f45f9bb | 1234 | |
504db471 JD |
1235 | di_trace = lookup_di_trace_from_stream(debug_it, stream); |
1236 | if (!di_trace) { | |
b4d4912f | 1237 | BT_LOGE_STR("Failed to find existing trace from stream."); |
504db471 JD |
1238 | goto error; |
1239 | } | |
1240 | ||
1241 | writer_stream = lookup_stream(debug_it, stream, di_trace); | |
4f45f9bb | 1242 | if (!writer_stream) { |
b4d4912f | 1243 | BT_LOGE_STR("Failed to find existing stream."); |
504db471 | 1244 | goto error; |
4f45f9bb JD |
1245 | } |
1246 | bt_get(writer_stream); | |
1247 | ||
1248 | goto end; | |
1249 | ||
1250 | error: | |
1251 | BT_PUT(writer_stream); | |
1252 | end: | |
1253 | bt_put(stream_class); | |
1254 | return writer_stream; | |
1255 | } | |
1256 | ||
1257 | BT_HIDDEN | |
1258 | struct bt_ctf_packet *debug_info_new_packet( | |
1259 | struct debug_info_iterator *debug_it, | |
1260 | struct bt_ctf_packet *packet) | |
1261 | { | |
1262 | struct bt_ctf_stream *stream = NULL, *writer_stream = NULL; | |
4f45f9bb | 1263 | struct bt_ctf_packet *writer_packet = NULL; |
2d64a1eb | 1264 | struct bt_ctf_field *packet_context = NULL; |
504db471 | 1265 | struct debug_info_trace *di_trace; |
4f45f9bb JD |
1266 | int int_ret; |
1267 | ||
1268 | stream = bt_ctf_packet_get_stream(packet); | |
b4d4912f | 1269 | assert(stream); |
4f45f9bb JD |
1270 | |
1271 | writer_stream = get_writer_stream(debug_it, packet, stream); | |
1272 | if (!writer_stream) { | |
b4d4912f | 1273 | BT_LOGE_STR("Failed to get writer stream."); |
4f45f9bb JD |
1274 | goto error; |
1275 | } | |
1276 | ||
504db471 JD |
1277 | di_trace = lookup_di_trace_from_stream(debug_it, stream); |
1278 | if (!di_trace) { | |
b4d4912f | 1279 | BT_LOGE_STR("Failed to find existing trace from stream."); |
504db471 JD |
1280 | goto error; |
1281 | } | |
1282 | ||
4f45f9bb JD |
1283 | /* |
1284 | * If a packet was already opened, close it and remove it from | |
1285 | * the HT. | |
1286 | */ | |
504db471 | 1287 | writer_packet = lookup_packet(debug_it, packet, di_trace); |
4f45f9bb | 1288 | if (writer_packet) { |
504db471 | 1289 | g_hash_table_remove(di_trace->packet_map, packet); |
4f45f9bb JD |
1290 | BT_PUT(writer_packet); |
1291 | } | |
1292 | ||
504db471 JD |
1293 | writer_packet = insert_new_packet(debug_it, packet, writer_stream, |
1294 | di_trace); | |
4f45f9bb | 1295 | if (!writer_packet) { |
b4d4912f | 1296 | BT_LOGE_STR("Failed to insert new packet."); |
4f45f9bb JD |
1297 | goto error; |
1298 | } | |
4f45f9bb | 1299 | |
2d64a1eb JD |
1300 | packet_context = bt_ctf_packet_get_context(packet); |
1301 | if (packet_context) { | |
9877e1aa JD |
1302 | int_ret = ctf_packet_copy_context(debug_it->err, |
1303 | packet, writer_stream, writer_packet); | |
1304 | if (int_ret < 0) { | |
b4d4912f | 1305 | BT_LOGE_STR("Failed to copy packet context."); |
2d64a1eb JD |
1306 | goto error; |
1307 | } | |
1308 | BT_PUT(packet_context); | |
4f45f9bb JD |
1309 | } |
1310 | ||
1c78e839 | 1311 | bt_get(writer_packet); |
4f45f9bb JD |
1312 | goto end; |
1313 | ||
1314 | error: | |
1315 | ||
1316 | end: | |
2d64a1eb | 1317 | bt_put(packet_context); |
4f45f9bb JD |
1318 | bt_put(writer_stream); |
1319 | bt_put(stream); | |
1320 | return writer_packet; | |
1321 | } | |
1322 | ||
1323 | BT_HIDDEN | |
1324 | struct bt_ctf_packet *debug_info_close_packet( | |
1325 | struct debug_info_iterator *debug_it, | |
1326 | struct bt_ctf_packet *packet) | |
1327 | { | |
1328 | struct bt_ctf_packet *writer_packet = NULL; | |
504db471 JD |
1329 | struct bt_ctf_stream *stream = NULL; |
1330 | struct debug_info_trace *di_trace; | |
1331 | ||
1332 | stream = bt_ctf_packet_get_stream(packet); | |
b4d4912f | 1333 | assert(stream); |
504db471 JD |
1334 | |
1335 | di_trace = lookup_di_trace_from_stream(debug_it, stream); | |
1336 | if (!di_trace) { | |
b4d4912f | 1337 | BT_LOGE_STR("Failed to find trace from stream."); |
504db471 JD |
1338 | goto end; |
1339 | } | |
4f45f9bb | 1340 | |
504db471 | 1341 | writer_packet = lookup_packet(debug_it, packet, di_trace); |
4f45f9bb | 1342 | if (!writer_packet) { |
b4d4912f | 1343 | BT_LOGE_STR("Failed to find existing packet."); |
4f45f9bb JD |
1344 | goto end; |
1345 | } | |
1c78e839 | 1346 | bt_get(writer_packet); |
504db471 | 1347 | g_hash_table_remove(di_trace->packet_map, packet); |
4f45f9bb JD |
1348 | |
1349 | end: | |
504db471 | 1350 | bt_put(stream); |
4f45f9bb JD |
1351 | return writer_packet; |
1352 | } | |
1353 | ||
504db471 JD |
1354 | BT_HIDDEN |
1355 | struct bt_ctf_stream *debug_info_stream_begin( | |
1356 | struct debug_info_iterator *debug_it, | |
1357 | struct bt_ctf_stream *stream) | |
1358 | { | |
cb0a5cf8 | 1359 | struct bt_ctf_stream *writer_stream = NULL; |
1c78e839 | 1360 | enum debug_info_stream_state *state; |
504db471 JD |
1361 | struct debug_info_trace *di_trace = NULL; |
1362 | ||
1363 | di_trace = lookup_di_trace_from_stream(debug_it, stream); | |
1364 | if (!di_trace) { | |
1365 | di_trace = insert_new_trace(debug_it, stream); | |
1366 | if (!di_trace) { | |
b4d4912f | 1367 | BT_LOGE_STR("Failed to insert new trace."); |
1c78e839 | 1368 | goto error; |
504db471 JD |
1369 | } |
1370 | } | |
1371 | ||
1c78e839 JD |
1372 | /* Set the stream as active */ |
1373 | state = g_hash_table_lookup(di_trace->stream_states, stream); | |
1374 | if (!state) { | |
1375 | if (di_trace->trace_static) { | |
b4d4912f | 1376 | BT_LOGE_STR("Failed to add a new stream, trace is static."); |
1c78e839 JD |
1377 | goto error; |
1378 | } | |
1379 | state = insert_new_stream_state(debug_it, di_trace, | |
1380 | stream); | |
ec273a88 | 1381 | if (!state) { |
b4d4912f | 1382 | BT_LOGE_STR("Failed to add new stream state."); |
ec273a88 JD |
1383 | goto error; |
1384 | } | |
1c78e839 JD |
1385 | } |
1386 | if (*state != DEBUG_INFO_UNKNOWN_STREAM) { | |
b4d4912f | 1387 | BT_LOGE("Unexpected stream state: state=%d", *state); |
1c78e839 JD |
1388 | goto error; |
1389 | } | |
1390 | *state = DEBUG_INFO_ACTIVE_STREAM; | |
1391 | ||
cb0a5cf8 JD |
1392 | writer_stream = lookup_stream(debug_it, stream, di_trace); |
1393 | if (!writer_stream) { | |
1394 | writer_stream = insert_new_stream(debug_it, stream, di_trace); | |
1395 | } | |
1c78e839 | 1396 | bt_get(writer_stream); |
504db471 | 1397 | |
1c78e839 JD |
1398 | goto end; |
1399 | ||
1400 | error: | |
1401 | BT_PUT(writer_stream); | |
504db471 JD |
1402 | end: |
1403 | return writer_stream; | |
1404 | } | |
1405 | ||
4f45f9bb JD |
1406 | BT_HIDDEN |
1407 | struct bt_ctf_stream *debug_info_stream_end(struct debug_info_iterator *debug_it, | |
1408 | struct bt_ctf_stream *stream) | |
1409 | { | |
0bb3da02 | 1410 | struct bt_ctf_stream *writer_stream = NULL; |
504db471 | 1411 | struct debug_info_trace *di_trace = NULL; |
1c78e839 | 1412 | enum debug_info_stream_state *state; |
504db471 JD |
1413 | |
1414 | di_trace = lookup_di_trace_from_stream(debug_it, stream); | |
1415 | if (!di_trace) { | |
b4d4912f | 1416 | BT_LOGE_STR("Failed to find existing trace from stream."); |
1c78e839 | 1417 | goto error; |
504db471 | 1418 | } |
4f45f9bb | 1419 | |
504db471 | 1420 | writer_stream = lookup_stream(debug_it, stream, di_trace); |
4f45f9bb | 1421 | if (!writer_stream) { |
b4d4912f | 1422 | BT_LOGE_STR("Failed to find existing stream."); |
1c78e839 | 1423 | goto error; |
4f45f9bb | 1424 | } |
1c78e839 JD |
1425 | /* |
1426 | * Take the ref on the stream and keep it until the notification | |
1427 | * is created. | |
1428 | */ | |
34101229 | 1429 | bt_get(writer_stream); |
1c78e839 JD |
1430 | |
1431 | state = g_hash_table_lookup(di_trace->stream_states, stream); | |
1432 | if (*state != DEBUG_INFO_ACTIVE_STREAM) { | |
b4d4912f | 1433 | BT_LOGE("Unexpected stream state: state=%d", *state); |
1c78e839 JD |
1434 | goto error; |
1435 | } | |
1436 | *state = DEBUG_INFO_COMPLETED_STREAM; | |
1437 | ||
504db471 | 1438 | g_hash_table_remove(di_trace->stream_map, stream); |
4f45f9bb | 1439 | |
1c78e839 JD |
1440 | if (di_trace->trace_static) { |
1441 | int trace_completed = 1; | |
1442 | ||
1443 | g_hash_table_foreach(di_trace->stream_states, | |
1444 | check_completed_trace, &trace_completed); | |
1445 | if (trace_completed) { | |
1446 | debug_info_close_trace(debug_it, di_trace); | |
1447 | g_hash_table_remove(debug_it->trace_map, | |
1448 | di_trace->trace); | |
1449 | } | |
1450 | } | |
1451 | ||
1452 | goto end; | |
1453 | ||
1454 | error: | |
1455 | BT_PUT(writer_stream); | |
1456 | ||
4f45f9bb JD |
1457 | end: |
1458 | return writer_stream; | |
1459 | } | |
1460 | ||
1461 | static | |
1462 | struct debug_info_source *lookup_debug_info(FILE *err, | |
1463 | struct bt_ctf_event *event, | |
1464 | struct debug_info *debug_info) | |
1465 | { | |
1466 | int64_t vpid; | |
1467 | uint64_t ip; | |
1468 | struct debug_info_source *dbg_info_src = NULL; | |
1469 | int ret; | |
1470 | ||
1471 | ret = get_stream_event_context_int_field_value(err, event, | |
1472 | "_vpid", &vpid); | |
1473 | if (ret) { | |
1474 | goto end; | |
1475 | } | |
1476 | ||
1477 | ret = get_stream_event_context_unsigned_int_field_value(err, event, | |
1478 | "_ip", &ip); | |
1479 | if (ret) { | |
1480 | goto end; | |
1481 | } | |
1482 | ||
1483 | /* Get debug info for this context. */ | |
1484 | dbg_info_src = debug_info_query(debug_info, vpid, ip); | |
1485 | ||
1486 | end: | |
1487 | return dbg_info_src; | |
1488 | } | |
1489 | ||
1490 | static | |
1491 | int set_debug_info_field(FILE *err, struct bt_ctf_field *debug_field, | |
1492 | struct debug_info_source *dbg_info_src, | |
1493 | struct debug_info_component *component) | |
1494 | { | |
2afcfbfb | 1495 | int i, nr_fields, ret = 0; |
4f45f9bb JD |
1496 | struct bt_ctf_field_type *debug_field_type = NULL; |
1497 | struct bt_ctf_field *field = NULL; | |
1498 | struct bt_ctf_field_type *field_type = NULL; | |
1499 | ||
1500 | debug_field_type = bt_ctf_field_get_type(debug_field); | |
b4d4912f | 1501 | assert(debug_field_type); |
4f45f9bb JD |
1502 | |
1503 | nr_fields = bt_ctf_field_type_structure_get_field_count(debug_field_type); | |
1504 | for (i = 0; i < nr_fields; i++) { | |
1505 | const char *field_name; | |
1506 | ||
1507 | if (bt_ctf_field_type_structure_get_field(debug_field_type, | |
1508 | &field_name, &field_type, i) < 0) { | |
b4d4912f JD |
1509 | BT_LOGE("Failed to get field from debug_info struct: field-name=\"%s\"", |
1510 | field_name); | |
4f45f9bb JD |
1511 | goto error; |
1512 | } | |
1513 | BT_PUT(field_type); | |
1514 | ||
1515 | field = bt_ctf_field_structure_get_field_by_index(debug_field, i); | |
1516 | if (!strcmp(field_name, "bin")) { | |
1517 | if (dbg_info_src && dbg_info_src->bin_path) { | |
1518 | GString *tmp = g_string_new(NULL); | |
1519 | ||
1520 | if (component->arg_full_path) { | |
1521 | g_string_printf(tmp, "%s%s", | |
1522 | dbg_info_src->bin_path, | |
1523 | dbg_info_src->bin_loc); | |
1524 | } else { | |
1525 | g_string_printf(tmp, "%s%s", | |
1526 | dbg_info_src->short_bin_path, | |
1527 | dbg_info_src->bin_loc); | |
1528 | } | |
1529 | ret = bt_ctf_field_string_set_value(field, tmp->str); | |
1530 | g_string_free(tmp, true); | |
1531 | } else { | |
1532 | ret = bt_ctf_field_string_set_value(field, ""); | |
1533 | } | |
1534 | } else if (!strcmp(field_name, "func")) { | |
1535 | if (dbg_info_src && dbg_info_src->func) { | |
1536 | ret = bt_ctf_field_string_set_value(field, | |
1537 | dbg_info_src->func); | |
1538 | } else { | |
1539 | ret = bt_ctf_field_string_set_value(field, ""); | |
1540 | } | |
1541 | } else if (!strcmp(field_name, "src")) { | |
1542 | if (dbg_info_src && dbg_info_src->src_path) { | |
1543 | GString *tmp = g_string_new(NULL); | |
1544 | ||
1545 | if (component->arg_full_path) { | |
1546 | g_string_printf(tmp, "%s:%" PRId64, | |
1547 | dbg_info_src->src_path, | |
1548 | dbg_info_src->line_no); | |
1549 | } else { | |
1550 | g_string_printf(tmp, "%s:%" PRId64, | |
1551 | dbg_info_src->short_src_path, | |
1552 | dbg_info_src->line_no); | |
1553 | } | |
1554 | ret = bt_ctf_field_string_set_value(field, tmp->str); | |
1555 | g_string_free(tmp, true); | |
1556 | } else { | |
1557 | ret = bt_ctf_field_string_set_value(field, ""); | |
1558 | } | |
1559 | } | |
1560 | BT_PUT(field); | |
1561 | if (ret) { | |
b4d4912f JD |
1562 | BT_LOGE("Failed to set value in debug-info struct: field-name=\"%s\"", |
1563 | field_name); | |
4f45f9bb JD |
1564 | goto error; |
1565 | } | |
1566 | } | |
1567 | ret = 0; | |
1568 | goto end; | |
1569 | ||
1570 | error: | |
1571 | ret = -1; | |
1572 | end: | |
1573 | bt_put(field_type); | |
1574 | bt_put(field); | |
1575 | bt_put(debug_field_type); | |
1576 | return ret; | |
1577 | } | |
1578 | ||
1579 | static | |
1580 | int copy_set_debug_info_stream_event_context(FILE *err, | |
1581 | struct bt_ctf_field *event_context, | |
1582 | struct bt_ctf_event *event, | |
1583 | struct bt_ctf_event *writer_event, | |
1584 | struct debug_info *debug_info, | |
1585 | struct debug_info_component *component) | |
1586 | { | |
08b6e8e8 JD |
1587 | struct bt_ctf_field_type *writer_event_context_type = NULL, |
1588 | *event_context_type = NULL; | |
4f45f9bb JD |
1589 | struct bt_ctf_field *writer_event_context = NULL; |
1590 | struct bt_ctf_field *field = NULL, *copy_field = NULL, *debug_field = NULL; | |
1591 | struct bt_ctf_field_type *field_type = NULL; | |
1592 | struct debug_info_source *dbg_info_src; | |
1593 | int ret, nr_fields, i; | |
1594 | ||
1595 | writer_event_context = bt_ctf_event_get_stream_event_context(writer_event); | |
b4d4912f | 1596 | assert(writer_event_context); |
4f45f9bb JD |
1597 | |
1598 | writer_event_context_type = bt_ctf_field_get_type(writer_event_context); | |
b4d4912f | 1599 | assert(writer_event_context_type); |
4f45f9bb | 1600 | |
08b6e8e8 | 1601 | event_context_type = bt_ctf_field_get_type(event_context); |
b4d4912f | 1602 | assert(event_context_type); |
08b6e8e8 | 1603 | |
4f45f9bb JD |
1604 | /* |
1605 | * If it is not a structure, we did not modify it to add the debug info | |
1606 | * fields, so just assign it as is. | |
1607 | */ | |
1487a16a | 1608 | if (bt_ctf_field_type_get_type_id(writer_event_context_type) != BT_CTF_FIELD_TYPE_ID_STRUCT) { |
4f45f9bb JD |
1609 | ret = bt_ctf_event_set_event_context(writer_event, event_context); |
1610 | goto end; | |
1611 | } | |
1612 | ||
1613 | dbg_info_src = lookup_debug_info(err, event, debug_info); | |
1614 | ||
1615 | nr_fields = bt_ctf_field_type_structure_get_field_count(writer_event_context_type); | |
1616 | for (i = 0; i < nr_fields; i++) { | |
1617 | const char *field_name; | |
1618 | ||
1619 | if (bt_ctf_field_type_structure_get_field(writer_event_context_type, | |
1620 | &field_name, &field_type, i) < 0) { | |
b4d4912f JD |
1621 | BT_LOGE("Failed to get field from event-context: field-name=\"%s\"", |
1622 | field_name); | |
4f45f9bb JD |
1623 | goto error; |
1624 | } | |
1625 | ||
08b6e8e8 JD |
1626 | /* |
1627 | * Prevent illegal access in the event_context. | |
1628 | */ | |
1629 | if (i < bt_ctf_field_type_structure_get_field_count(event_context_type)) { | |
1630 | field = bt_ctf_field_structure_get_field_by_index(event_context, i); | |
1631 | } | |
4f45f9bb JD |
1632 | /* |
1633 | * The debug_info field, only exists in the writer event or | |
1634 | * if it was set by a earlier pass of the debug_info plugin. | |
4f45f9bb JD |
1635 | */ |
1636 | if (!strcmp(field_name, component->arg_debug_info_field_name) && | |
1637 | !field) { | |
1638 | debug_field = bt_ctf_field_structure_get_field_by_index( | |
1639 | writer_event_context, i); | |
b4d4912f JD |
1640 | assert(debug_field); |
1641 | ||
4f45f9bb JD |
1642 | ret = set_debug_info_field(err, debug_field, |
1643 | dbg_info_src, component); | |
1644 | if (ret) { | |
b4d4912f | 1645 | BT_LOGE_STR("Failed to set debug_info field."); |
4f45f9bb JD |
1646 | goto error; |
1647 | } | |
1648 | BT_PUT(debug_field); | |
1649 | } else { | |
1650 | copy_field = bt_ctf_field_copy(field); | |
1651 | if (!copy_field) { | |
b4d4912f JD |
1652 | BT_LOGE("Failed to copy field: field-name=\"%s\"", |
1653 | field_name); | |
4f45f9bb JD |
1654 | goto error; |
1655 | } | |
1656 | ||
2225de6b PP |
1657 | ret = bt_ctf_field_structure_set_field_by_name( |
1658 | writer_event_context, | |
4f45f9bb JD |
1659 | field_name, copy_field); |
1660 | if (ret) { | |
b4d4912f JD |
1661 | BT_LOGE("Failed to set field: field-name=\"%s\"", |
1662 | field_name); | |
4f45f9bb JD |
1663 | goto error; |
1664 | } | |
1665 | BT_PUT(copy_field); | |
1666 | } | |
1667 | BT_PUT(field_type); | |
1668 | BT_PUT(field); | |
1669 | } | |
1670 | ||
1671 | ret = 0; | |
1672 | goto end; | |
1673 | ||
1674 | error: | |
1675 | ret = -1; | |
1676 | end: | |
08b6e8e8 | 1677 | bt_put(event_context_type); |
4f45f9bb JD |
1678 | bt_put(writer_event_context_type); |
1679 | bt_put(writer_event_context); | |
1680 | bt_put(field); | |
1681 | bt_put(copy_field); | |
1682 | bt_put(debug_field); | |
1683 | bt_put(field_type); | |
1684 | return ret; | |
1685 | } | |
1686 | ||
1687 | static | |
1688 | struct bt_ctf_clock_class *stream_class_get_clock_class(FILE *err, | |
1689 | struct bt_ctf_stream_class *stream_class) | |
1690 | { | |
1691 | struct bt_ctf_trace *trace = NULL; | |
1692 | struct bt_ctf_clock_class *clock_class = NULL; | |
1693 | ||
1694 | trace = bt_ctf_stream_class_get_trace(stream_class); | |
b4d4912f | 1695 | assert(trace); |
4f45f9bb | 1696 | |
290b95cc MD |
1697 | if (!bt_ctf_trace_get_clock_class_count(trace)) { |
1698 | /* No clock. */ | |
1699 | goto end; | |
1700 | } | |
1701 | ||
4f45f9bb | 1702 | /* FIXME multi-clock? */ |
9ac68eb1 | 1703 | clock_class = bt_ctf_trace_get_clock_class_by_index(trace, 0); |
4f45f9bb JD |
1704 | |
1705 | bt_put(trace); | |
1706 | ||
1707 | end: | |
1708 | return clock_class; | |
1709 | } | |
1710 | ||
1711 | static | |
1712 | struct bt_ctf_clock_class *event_get_clock_class(FILE *err, struct bt_ctf_event *event) | |
1713 | { | |
1714 | struct bt_ctf_event_class *event_class = NULL; | |
1715 | struct bt_ctf_stream_class *stream_class = NULL; | |
1716 | struct bt_ctf_clock_class *clock_class = NULL; | |
1717 | ||
1718 | event_class = bt_ctf_event_get_class(event); | |
b4d4912f | 1719 | assert(event_class); |
4f45f9bb JD |
1720 | |
1721 | stream_class = bt_ctf_event_class_get_stream_class(event_class); | |
b4d4912f | 1722 | assert(stream_class); |
4f45f9bb JD |
1723 | |
1724 | clock_class = stream_class_get_clock_class(err, stream_class); | |
1725 | goto end; | |
1726 | ||
4f45f9bb JD |
1727 | end: |
1728 | bt_put(stream_class); | |
1729 | bt_put(event_class); | |
1730 | return clock_class; | |
1731 | } | |
1732 | ||
1733 | static | |
1734 | int set_event_clock_value(FILE *err, struct bt_ctf_event *event, | |
1735 | struct bt_ctf_event *writer_event) | |
1736 | { | |
1737 | struct bt_ctf_clock_class *clock_class = NULL; | |
1738 | struct bt_ctf_clock_value *clock_value = NULL; | |
1081db08 | 1739 | int ret = 0; |
4f45f9bb JD |
1740 | |
1741 | clock_class = event_get_clock_class(err, event); | |
1742 | if (!clock_class) { | |
290b95cc MD |
1743 | /* No clock on input trace. */ |
1744 | goto end; | |
4f45f9bb JD |
1745 | } |
1746 | ||
1747 | clock_value = bt_ctf_event_get_clock_value(event, clock_class); | |
1748 | if (!clock_value) { | |
b4d4912f JD |
1749 | ret = 0; |
1750 | goto end; | |
4f45f9bb JD |
1751 | } |
1752 | ||
1753 | /* | |
1754 | * We share the same clocks, so we can assign the clock value to the | |
1755 | * writer event. | |
1756 | */ | |
1757 | ret = bt_ctf_event_set_clock_value(writer_event, clock_value); | |
1758 | if (ret) { | |
b4d4912f | 1759 | BT_LOGE_STR("Failed to set clock value."); |
4f45f9bb JD |
1760 | goto error; |
1761 | } | |
1762 | ||
1763 | ret = 0; | |
1764 | goto end; | |
1765 | ||
1766 | error: | |
1767 | ret = -1; | |
1768 | end: | |
1769 | bt_put(clock_class); | |
1770 | bt_put(clock_value); | |
1771 | return ret; | |
1772 | } | |
1773 | ||
1774 | static | |
1775 | struct bt_ctf_event *debug_info_copy_event(FILE *err, struct bt_ctf_event *event, | |
1776 | struct bt_ctf_event_class *writer_event_class, | |
1777 | struct debug_info *debug_info, | |
1778 | struct debug_info_component *component) | |
1779 | { | |
1780 | struct bt_ctf_event *writer_event = NULL; | |
f6f999a3 | 1781 | struct bt_ctf_field *field = NULL, *copy_field = NULL; |
4f45f9bb JD |
1782 | int ret; |
1783 | ||
1784 | writer_event = bt_ctf_event_create(writer_event_class); | |
1785 | if (!writer_event) { | |
b4d4912f | 1786 | BT_LOGE_STR("Failed to create new event."); |
4f45f9bb JD |
1787 | goto error; |
1788 | } | |
1789 | ||
1790 | ret = set_event_clock_value(err, event, writer_event); | |
1791 | if (ret) { | |
b4d4912f | 1792 | BT_LOGE_STR("Failed to set clock value."); |
4f45f9bb JD |
1793 | goto error; |
1794 | } | |
1795 | ||
60ef553b | 1796 | /* Optional field, so it can fail silently. */ |
4f45f9bb | 1797 | field = bt_ctf_event_get_header(event); |
60ef553b JD |
1798 | if (field) { |
1799 | ret = ctf_copy_event_header(err, event, writer_event_class, | |
1800 | writer_event, field); | |
1801 | if (ret) { | |
b4d4912f | 1802 | BT_LOGE_STR("Failed to copy event header."); |
60ef553b JD |
1803 | goto error; |
1804 | } | |
1805 | BT_PUT(field); | |
4f45f9bb | 1806 | } |
4f45f9bb JD |
1807 | |
1808 | /* Optional field, so it can fail silently. */ | |
1809 | field = bt_ctf_event_get_stream_event_context(event); | |
1810 | if (field) { | |
1811 | ret = copy_set_debug_info_stream_event_context(err, | |
1812 | field, event, writer_event, debug_info, | |
1813 | component); | |
1814 | if (ret < 0) { | |
b4d4912f | 1815 | BT_LOGE_STR("Failed to debug_info stream event context."); |
4f45f9bb JD |
1816 | goto error; |
1817 | } | |
1818 | BT_PUT(field); | |
1819 | } | |
1820 | ||
1821 | /* Optional field, so it can fail silently. */ | |
1822 | field = bt_ctf_event_get_event_context(event); | |
60ef553b JD |
1823 | if (field) { |
1824 | copy_field = bt_ctf_field_copy(field); | |
1825 | if (!copy_field) { | |
b4d4912f | 1826 | BT_LOGE_STR("Failed to copy field."); |
60ef553b JD |
1827 | goto error; |
1828 | } | |
4f45f9bb JD |
1829 | ret = bt_ctf_event_set_event_context(writer_event, copy_field); |
1830 | if (ret < 0) { | |
b4d4912f | 1831 | BT_LOGE_STR("Failed to set event_context."); |
4f45f9bb JD |
1832 | goto error; |
1833 | } | |
1834 | BT_PUT(copy_field); | |
60ef553b | 1835 | BT_PUT(field); |
4f45f9bb | 1836 | } |
4f45f9bb | 1837 | |
9ac68eb1 | 1838 | field = bt_ctf_event_get_event_payload(event); |
b4d4912f JD |
1839 | assert(field); |
1840 | ||
4f45f9bb JD |
1841 | copy_field = bt_ctf_field_copy(field); |
1842 | if (copy_field) { | |
9ac68eb1 | 1843 | ret = bt_ctf_event_set_event_payload(writer_event, copy_field); |
4f45f9bb | 1844 | if (ret < 0) { |
b4d4912f | 1845 | BT_LOGE_STR("Failed to set event payload."); |
4f45f9bb JD |
1846 | goto error; |
1847 | } | |
1848 | BT_PUT(copy_field); | |
1849 | } | |
1850 | BT_PUT(field); | |
1851 | ||
1852 | goto end; | |
1853 | ||
1854 | error: | |
1855 | BT_PUT(writer_event); | |
1856 | end: | |
1857 | bt_put(copy_field); | |
1858 | bt_put(field); | |
1859 | return writer_event; | |
1860 | } | |
1861 | ||
1862 | BT_HIDDEN | |
1863 | struct bt_ctf_event *debug_info_output_event( | |
1864 | struct debug_info_iterator *debug_it, | |
1865 | struct bt_ctf_event *event) | |
1866 | { | |
1867 | struct bt_ctf_event_class *event_class = NULL, *writer_event_class = NULL; | |
1868 | struct bt_ctf_stream_class *stream_class = NULL, *writer_stream_class = NULL; | |
1869 | struct bt_ctf_event *writer_event = NULL; | |
f6f999a3 | 1870 | struct bt_ctf_packet *packet = NULL, *writer_packet = NULL; |
4f45f9bb | 1871 | struct bt_ctf_trace *writer_trace = NULL; |
504db471 JD |
1872 | struct bt_ctf_stream *stream = NULL; |
1873 | struct debug_info_trace *di_trace; | |
4f45f9bb | 1874 | struct debug_info *debug_info; |
4f45f9bb JD |
1875 | int int_ret; |
1876 | ||
1877 | event_class = bt_ctf_event_get_class(event); | |
b4d4912f | 1878 | assert(event_class); |
4f45f9bb JD |
1879 | |
1880 | stream_class = bt_ctf_event_class_get_stream_class(event_class); | |
b4d4912f JD |
1881 | assert(stream_class); |
1882 | ||
504db471 | 1883 | stream = bt_ctf_event_get_stream(event); |
b4d4912f JD |
1884 | assert(stream); |
1885 | ||
504db471 JD |
1886 | di_trace = lookup_di_trace_from_stream(debug_it, stream); |
1887 | if (!di_trace) { | |
b4d4912f | 1888 | BT_LOGE_STR("Failed to find existing trace from stream."); |
504db471 JD |
1889 | goto error; |
1890 | } | |
4f45f9bb JD |
1891 | |
1892 | writer_stream_class = g_hash_table_lookup( | |
504db471 | 1893 | di_trace->stream_class_map, |
4f45f9bb | 1894 | (gpointer) stream_class); |
504db471 | 1895 | if (!writer_stream_class) { |
b4d4912f | 1896 | BT_LOGE_STR("Failed to find existing stream_class."); |
4f45f9bb JD |
1897 | goto error; |
1898 | } | |
504db471 | 1899 | bt_get(writer_stream_class); |
4f45f9bb JD |
1900 | |
1901 | writer_event_class = get_event_class(debug_it, | |
1902 | writer_stream_class, event_class); | |
1903 | if (!writer_event_class) { | |
1904 | writer_event_class = ctf_copy_event_class(debug_it->err, | |
1905 | event_class); | |
1906 | if (!writer_event_class) { | |
b4d4912f | 1907 | BT_LOGE_STR("Failed to copy event_class."); |
4f45f9bb JD |
1908 | goto error; |
1909 | } | |
1910 | int_ret = bt_ctf_stream_class_add_event_class( | |
1911 | writer_stream_class, writer_event_class); | |
1912 | if (int_ret) { | |
b4d4912f | 1913 | BT_LOGE_STR("Failed to add event_class."); |
4f45f9bb JD |
1914 | goto error; |
1915 | } | |
1916 | } | |
1917 | ||
1918 | writer_trace = bt_ctf_stream_class_get_trace(writer_stream_class); | |
b4d4912f | 1919 | assert(writer_trace); |
4f45f9bb | 1920 | |
504db471 | 1921 | debug_info = get_trace_debug_info(debug_it, writer_trace, di_trace); |
4f45f9bb JD |
1922 | if (debug_info) { |
1923 | debug_info_handle_event(debug_it->err, event, debug_info); | |
1924 | } | |
1925 | ||
1926 | writer_event = debug_info_copy_event(debug_it->err, event, | |
1927 | writer_event_class, debug_info, | |
1928 | debug_it->debug_info_component); | |
1929 | if (!writer_event) { | |
b4d4912f | 1930 | BT_LOGE("Failed to copy event: event-class-name=\"%s\"", |
4f45f9bb JD |
1931 | bt_ctf_event_class_get_name(writer_event_class)); |
1932 | goto error; | |
1933 | } | |
1934 | ||
1935 | packet = bt_ctf_event_get_packet(event); | |
b4d4912f | 1936 | assert(packet); |
4f45f9bb | 1937 | |
504db471 | 1938 | writer_packet = lookup_packet(debug_it, packet, di_trace); |
4f45f9bb | 1939 | if (!writer_packet) { |
b4d4912f | 1940 | BT_LOGE_STR("Failed to find existing packet."); |
4f45f9bb JD |
1941 | goto error; |
1942 | } | |
1943 | bt_get(writer_packet); | |
1944 | ||
1945 | int_ret = bt_ctf_event_set_packet(writer_event, writer_packet); | |
1946 | if (int_ret < 0) { | |
b4d4912f | 1947 | BT_LOGE("Failed to append event to event-class-name=\"%s\"", |
4f45f9bb JD |
1948 | bt_ctf_event_class_get_name(writer_event_class)); |
1949 | goto error; | |
1950 | } | |
1951 | ||
1952 | /* Keep the reference on the writer event */ | |
1953 | goto end; | |
1954 | ||
1955 | error: | |
1956 | BT_PUT(writer_event); | |
1957 | ||
1958 | end: | |
504db471 | 1959 | bt_put(stream); |
4f45f9bb JD |
1960 | bt_put(writer_trace); |
1961 | bt_put(writer_packet); | |
1962 | bt_put(packet); | |
1963 | bt_put(writer_event_class); | |
1964 | bt_put(writer_stream_class); | |
1965 | bt_put(stream_class); | |
1966 | bt_put(event_class); | |
1967 | return writer_event; | |
1968 | } |