67b24f84f3dd450c9e55b697456bf42c4f013c62
[babeltrace.git] / src / plugins / lttng-utils / debug-info / trace-ir-mapping.c
1 /*
2 * Babeltrace - Mapping of IR metadata and data object between input and output
3 * trace
4 *
5 * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
6 * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
7 * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 #define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-MAPPING"
29 #include "logging.h"
30
31 #include <stdbool.h>
32
33 #include "common/assert.h"
34 #include <babeltrace2/babeltrace.h>
35 /* For bt_property_availability */
36 #include <babeltrace2/property.h>
37
38 #include "debug-info.h"
39 #include "trace-ir-data-copy.h"
40 #include "trace-ir-mapping.h"
41 #include "trace-ir-metadata-copy.h"
42
43 static
44 bt_trace_class *create_new_mapped_trace_class(struct trace_ir_maps *ir_maps,
45 const bt_trace_class *in_trace_class)
46 {
47 int ret;
48 bt_trace_class *out_trace_class;
49
50 BT_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class);
51
52 BT_ASSERT(ir_maps);
53 BT_ASSERT(in_trace_class);
54
55 /* Create the ouput trace class. */
56 out_trace_class = bt_trace_class_create(ir_maps->self_comp);
57 if (!out_trace_class) {
58 BT_LOGE_STR("Error create output trace class");
59 goto end;
60 }
61
62 /* If not, create a new one and add it to the mapping. */
63 ret = copy_trace_class_content(in_trace_class, out_trace_class);
64 if (ret) {
65 BT_LOGE_STR("Error copy content to output trace class");
66 out_trace_class = NULL;
67 goto end;
68 }
69
70 BT_LOGD("Created new mapped trace class: in-tc-addr=%p, out-tc-addr=%p",
71 in_trace_class, out_trace_class);
72
73 end:
74 return out_trace_class;
75 }
76
77 static
78 bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps,
79 const bt_trace *in_trace)
80 {
81 bt_trace *out_trace;
82 const bt_trace_class *in_trace_class;
83 struct trace_ir_metadata_maps *metadata_maps;
84
85 BT_LOGD("Creating new mapped trace: in-t-addr=%p", in_trace);
86 BT_ASSERT(ir_maps);
87 BT_ASSERT(in_trace);
88
89 in_trace_class = bt_trace_borrow_class_const(in_trace);
90 metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps,
91 in_trace_class);
92
93 if (!metadata_maps->output_trace_class) {
94 metadata_maps->output_trace_class =
95 create_new_mapped_trace_class(ir_maps, in_trace_class);
96 if (!metadata_maps->output_trace_class) {
97 out_trace = NULL;
98 goto end;
99 }
100 }
101
102 out_trace = bt_trace_create(metadata_maps->output_trace_class);
103 if (!out_trace) {
104 BT_LOGE_STR("Error create output trace");
105 goto end;
106 }
107
108 /* If not, create a new one and add it to the mapping. */
109 copy_trace_content(in_trace, out_trace);
110
111 BT_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p",
112 in_trace, out_trace);
113 end:
114 return out_trace;
115 }
116
117 static
118 bt_stream_class *borrow_mapped_stream_class(struct trace_ir_metadata_maps *md_maps,
119 const bt_stream_class *in_stream_class)
120 {
121 BT_ASSERT(md_maps);
122 BT_ASSERT(in_stream_class);
123
124 return g_hash_table_lookup(md_maps->stream_class_map,
125 (gpointer) in_stream_class);
126 }
127
128 static
129 bt_stream_class *create_new_mapped_stream_class(struct trace_ir_maps *ir_maps,
130 const bt_stream_class *in_stream_class)
131 {
132 int ret;
133 bt_stream_class *out_stream_class;
134 struct trace_ir_metadata_maps *md_maps;
135
136 BT_LOGD("Creating new mapped stream class: in-sc-addr=%p",
137 in_stream_class);
138
139 md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps,
140 in_stream_class);
141
142 BT_ASSERT(md_maps);
143 BT_ASSERT(in_stream_class);
144 BT_ASSERT(!borrow_mapped_stream_class(md_maps, in_stream_class));
145
146 /* Create an out_stream_class. */
147 out_stream_class = bt_stream_class_create_with_id(
148 md_maps->output_trace_class,
149 bt_stream_class_get_id(in_stream_class));
150 if (!out_stream_class) {
151 BT_LOGE_STR("Error create output stream class");
152 goto end;
153 }
154
155 /* If not, create a new one and add it to the mapping. */
156 ret = copy_stream_class_content(ir_maps, in_stream_class,
157 out_stream_class);
158 if (ret) {
159 BT_LOGE_STR("Error copy content to output stream class");
160 out_stream_class = NULL;
161 goto end;
162 }
163
164 g_hash_table_insert(md_maps->stream_class_map,
165 (gpointer) in_stream_class, out_stream_class);
166
167 BT_LOGD("Created new mapped stream class: in-sc-addr=%p, out-sc-addr=%p",
168 in_stream_class, out_stream_class);
169
170 end:
171 return out_stream_class;
172 }
173
174 static
175 bt_stream *borrow_mapped_stream(struct trace_ir_data_maps *d_maps,
176 const bt_stream *in_stream)
177 {
178 BT_ASSERT(d_maps);
179 BT_ASSERT(in_stream);
180
181 return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream);
182 }
183
184 BT_HIDDEN
185 bt_stream *trace_ir_mapping_create_new_mapped_stream(
186 struct trace_ir_maps *ir_maps,
187 const bt_stream *in_stream)
188 {
189 struct trace_ir_data_maps *d_maps;
190 struct trace_ir_metadata_maps *md_maps;
191 const bt_stream_class *in_stream_class;
192 const bt_trace *in_trace;
193 bt_stream_class *out_stream_class;
194 bt_stream *out_stream = NULL;
195
196 BT_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream);
197
198 BT_ASSERT(ir_maps);
199 BT_ASSERT(in_stream);
200
201 in_trace = bt_stream_borrow_trace_const(in_stream);
202
203 d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
204 if (!d_maps->output_trace) {
205 d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace);
206 if (!d_maps->output_trace) {
207 goto end;
208 }
209 }
210
211 BT_ASSERT(d_maps->output_trace);
212 BT_ASSERT(!borrow_mapped_stream(d_maps, in_stream));
213
214 in_stream_class = bt_stream_borrow_class_const(in_stream);
215 md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class);
216 out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
217 if (!out_stream_class) {
218 out_stream_class = create_new_mapped_stream_class(ir_maps,
219 in_stream_class);
220 if (!out_stream_class) {
221 goto end;
222 }
223 }
224 BT_ASSERT(out_stream_class);
225
226 out_stream = bt_stream_create_with_id(out_stream_class,
227 d_maps->output_trace, bt_stream_get_id(in_stream));
228 if (!out_stream) {
229 BT_LOGE_STR("Error creating output stream");
230 goto end;
231 }
232 /*
233 * Release our ref since the trace object will be managing the life
234 * time of the stream objects.
235 */
236
237 copy_stream_content(in_stream, out_stream);
238
239 g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream,
240 out_stream);
241
242 BT_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p",
243 in_stream, out_stream);
244
245 end:
246 return out_stream;
247 }
248
249 BT_HIDDEN
250 bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps,
251 const bt_stream *in_stream)
252 {
253 BT_ASSERT(ir_maps);
254 BT_ASSERT(in_stream);
255 struct trace_ir_data_maps *d_maps;
256
257 d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
258 /* Return the mapped stream. */
259 return borrow_mapped_stream(d_maps, in_stream);
260 }
261
262 static inline
263 bt_event_class *borrow_mapped_event_class(struct trace_ir_metadata_maps *md_maps,
264 const bt_event_class *in_event_class)
265 {
266 return g_hash_table_lookup(md_maps->event_class_map,
267 (gpointer) in_event_class);
268 }
269
270 BT_HIDDEN
271 bt_event_class *trace_ir_mapping_create_new_mapped_event_class(
272 struct trace_ir_maps *ir_maps,
273 const bt_event_class *in_event_class)
274 {
275 bt_event_class *out_event_class;
276 const bt_trace_class *in_trace_class;
277 const bt_stream_class *in_stream_class;
278 bt_stream_class *out_stream_class;
279 struct trace_ir_metadata_maps *md_maps;
280 int ret;
281
282 BT_LOGD("Creating new mapped event class: in-ec-addr=%p",
283 in_event_class);
284
285 BT_ASSERT(ir_maps);
286 BT_ASSERT(in_event_class);
287
288 in_trace_class = bt_stream_class_borrow_trace_class_const(
289 bt_event_class_borrow_stream_class_const(
290 in_event_class));
291
292 md_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, in_trace_class);
293
294 BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class));
295
296 in_stream_class =
297 bt_event_class_borrow_stream_class_const(in_event_class);
298 BT_ASSERT(in_stream_class);
299
300 /* Get the right output stream class to add the new event class to. */
301 out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
302 BT_ASSERT(out_stream_class);
303
304 /* Create an output event class. */
305 out_event_class = bt_event_class_create_with_id(out_stream_class,
306 bt_event_class_get_id(in_event_class));
307 if (!out_event_class) {
308 BT_LOGE_STR("Error creating output event class");
309 goto end;
310 }
311
312 /* If not, create a new one and add it to the mapping. */
313 ret = copy_event_class_content(ir_maps, in_event_class,
314 out_event_class);
315 if (ret) {
316 BT_LOGE_STR("Error copy content to output event class");
317 out_event_class = NULL;
318 goto end;
319 }
320
321 g_hash_table_insert(md_maps->event_class_map,
322 (gpointer) in_event_class, out_event_class);
323
324 BT_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p",
325 in_event_class, out_event_class);
326
327 end:
328 return out_event_class;
329 }
330
331 BT_HIDDEN
332 bt_event_class *trace_ir_mapping_borrow_mapped_event_class(
333 struct trace_ir_maps *ir_maps,
334 const bt_event_class *in_event_class)
335 {
336 struct trace_ir_metadata_maps *md_maps;
337
338 BT_ASSERT(ir_maps);
339 BT_ASSERT(in_event_class);
340
341 md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, in_event_class);
342
343 /* Return the mapped event_class. */
344 return borrow_mapped_event_class(md_maps, in_event_class);
345 }
346
347 static inline
348 bt_packet *borrow_mapped_packet(struct trace_ir_data_maps *d_maps,
349 const bt_packet *in_packet)
350 {
351 BT_ASSERT(d_maps);
352 BT_ASSERT(in_packet);
353
354 return g_hash_table_lookup(d_maps->packet_map,
355 (gpointer) in_packet);
356 }
357
358 BT_HIDDEN
359 bt_packet *trace_ir_mapping_create_new_mapped_packet(
360 struct trace_ir_maps *ir_maps,
361 const bt_packet *in_packet)
362 {
363 struct trace_ir_data_maps *d_maps;
364 const bt_trace *in_trace;
365 const bt_stream *in_stream;
366 bt_packet *out_packet;
367 bt_stream *out_stream;
368
369 BT_LOGD("Creating new mapped packet: in-p-addr=%p", in_packet);
370
371 in_stream = bt_packet_borrow_stream_const(in_packet);
372 in_trace = bt_stream_borrow_trace_const(in_stream);
373 d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
374
375 /* There should never be a mapped packet. */
376 BT_ASSERT(!borrow_mapped_packet(d_maps, in_packet));
377
378 BT_ASSERT(in_stream);
379
380 /* Get output stream corresponding to this input stream. */
381 out_stream = borrow_mapped_stream(d_maps, in_stream);
382 BT_ASSERT(out_stream);
383
384 /* Create the output packet. */
385 out_packet = bt_packet_create(out_stream);
386 if (!out_packet) {
387 BT_LOGE_STR("Error create output packet");
388 goto end;
389 }
390
391 /*
392 * Release our ref since the stream object will be managing the life
393 * time of the packet objects.
394 */
395 copy_packet_content(in_packet, out_packet);
396
397 g_hash_table_insert(d_maps->packet_map,
398 (gpointer) in_packet, out_packet);
399
400 BT_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p",
401 in_packet, out_packet);
402
403 end:
404 return out_packet;
405 }
406
407 BT_HIDDEN
408 bt_packet *trace_ir_mapping_borrow_mapped_packet(struct trace_ir_maps *ir_maps,
409 const bt_packet *in_packet)
410 {
411 struct trace_ir_data_maps *d_maps;
412 BT_ASSERT(ir_maps);
413 BT_ASSERT(in_packet);
414
415 d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
416
417 return borrow_mapped_packet(d_maps, in_packet);
418 }
419
420 BT_HIDDEN
421 void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps,
422 const bt_packet *in_packet)
423 {
424 gboolean ret;
425
426 struct trace_ir_data_maps *d_maps;
427 BT_ASSERT(ir_maps);
428 BT_ASSERT(in_packet);
429
430 d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
431
432 ret = g_hash_table_remove(d_maps->packet_map, in_packet);
433
434 BT_ASSERT(ret);
435 }
436
437 BT_HIDDEN
438 void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps,
439 const bt_stream *in_stream)
440 {
441 gboolean ret;
442 struct trace_ir_data_maps *d_maps;
443
444 BT_ASSERT(ir_maps);
445 BT_ASSERT(in_stream);
446
447 d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
448
449 ret = g_hash_table_remove(d_maps->stream_map, in_stream);
450
451 BT_ASSERT(ret);
452 }
453
454 static
455 void trace_ir_metadata_maps_remove_func(const bt_trace_class *in_trace_class,
456 void *data)
457 {
458 struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
459 if (maps->metadata_maps) {
460 gboolean ret;
461 ret = g_hash_table_remove(maps->metadata_maps,
462 (gpointer) in_trace_class);
463 BT_ASSERT(ret);
464 }
465 }
466
467 static
468 void trace_ir_data_maps_remove_func(const bt_trace *in_trace, void *data)
469 {
470 struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
471 if (maps->data_maps) {
472 gboolean ret;
473 ret = g_hash_table_remove(maps->data_maps, (gpointer) in_trace);
474 BT_ASSERT(ret);
475 }
476 }
477
478 struct trace_ir_data_maps *trace_ir_data_maps_create(struct trace_ir_maps *ir_maps,
479 const bt_trace *in_trace)
480 {
481 struct trace_ir_data_maps *d_maps =
482 g_new0(struct trace_ir_data_maps, 1);
483 if (!d_maps) {
484 BT_LOGE_STR("Error allocating trace_ir_maps");
485 goto error;
486 }
487
488 d_maps->input_trace = in_trace;
489
490 /* Create the hashtables used to map data objects. */
491 d_maps->stream_map = g_hash_table_new_full(g_direct_hash,
492 g_direct_equal, NULL,(GDestroyNotify) bt_stream_put_ref);
493 d_maps->packet_map = g_hash_table_new_full(g_direct_hash,
494 g_direct_equal, NULL,(GDestroyNotify) bt_packet_put_ref);
495
496 bt_trace_add_destruction_listener(in_trace, trace_ir_data_maps_remove_func,
497 ir_maps, &d_maps->destruction_listener_id);
498 error:
499 return d_maps;
500 }
501
502 struct trace_ir_metadata_maps *trace_ir_metadata_maps_create(
503 struct trace_ir_maps *ir_maps,
504 const bt_trace_class *in_trace_class)
505 {
506 struct trace_ir_metadata_maps *md_maps =
507 g_new0(struct trace_ir_metadata_maps, 1);
508 if (!md_maps) {
509 BT_LOGE_STR("Error allocating trace_ir_maps");
510 goto error;
511 }
512
513 md_maps->input_trace_class = in_trace_class;
514 /*
515 * Create the field class resolving context. This is needed to keep
516 * track of the field class already copied in order to do the field
517 * path resolution correctly.
518 */
519 md_maps->fc_resolving_ctx =
520 g_new0(struct field_class_resolving_context, 1);
521 if (!md_maps->fc_resolving_ctx) {
522 BT_LOGE_STR("Error allocating field_class_resolving_context");
523 goto error;
524 }
525
526 /* Create the hashtables used to map metadata objects. */
527 md_maps->stream_class_map = g_hash_table_new_full(g_direct_hash,
528 g_direct_equal, NULL, (GDestroyNotify) bt_stream_class_put_ref);
529 md_maps->event_class_map = g_hash_table_new_full(g_direct_hash,
530 g_direct_equal, NULL, (GDestroyNotify) bt_event_class_put_ref);
531 md_maps->field_class_map = g_hash_table_new_full(g_direct_hash,
532 g_direct_equal, NULL, (GDestroyNotify) bt_field_class_put_ref);
533 md_maps->clock_class_map = g_hash_table_new_full(g_direct_hash,
534 g_direct_equal, NULL, (GDestroyNotify) bt_clock_class_put_ref);
535
536 bt_trace_class_add_destruction_listener(in_trace_class,
537 trace_ir_metadata_maps_remove_func,
538 ir_maps, &md_maps->destruction_listener_id);
539 error:
540 return md_maps;
541 }
542
543 BT_HIDDEN
544 void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps)
545 {
546 bt_trace_status status;
547 if (!maps) {
548 return;
549 }
550
551 if (maps->packet_map) {
552 g_hash_table_destroy(maps->packet_map);
553 }
554
555 if (maps->stream_map) {
556 g_hash_table_destroy(maps->stream_map);
557 }
558
559 if (maps->output_trace) {
560 bt_trace_put_ref(maps->output_trace);
561 }
562
563 status = bt_trace_remove_destruction_listener(maps->input_trace,
564 maps->destruction_listener_id);
565 if (status != BT_TRACE_STATUS_OK) {
566 BT_LOGD("Trace destruction listener removal failed.");
567 }
568
569 g_free(maps);
570 }
571
572 BT_HIDDEN
573 void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps)
574 {
575 bt_trace_class_status status;
576 if (!maps) {
577 return;
578 }
579
580 if (maps->stream_class_map) {
581 g_hash_table_destroy(maps->stream_class_map);
582 }
583
584 if (maps->event_class_map) {
585 g_hash_table_destroy(maps->event_class_map);
586 }
587
588 if (maps->field_class_map) {
589 g_hash_table_destroy(maps->field_class_map);
590 }
591
592 if (maps->clock_class_map) {
593 g_hash_table_destroy(maps->clock_class_map);
594 }
595
596 if (maps->fc_resolving_ctx) {
597 g_free(maps->fc_resolving_ctx);
598 }
599
600 if (maps->output_trace_class) {
601 bt_trace_class_put_ref(maps->output_trace_class);
602 }
603
604 status = bt_trace_class_remove_destruction_listener(maps->input_trace_class,
605 maps->destruction_listener_id);
606 if (status != BT_TRACE_CLASS_STATUS_OK) {
607 BT_LOGD("Trace destruction listener removal failed.");
608 }
609
610 g_free(maps);
611 }
612
613 void trace_ir_maps_clear(struct trace_ir_maps *maps)
614 {
615 if (maps->data_maps) {
616 g_hash_table_remove_all(maps->data_maps);
617 }
618
619 if (maps->metadata_maps) {
620 g_hash_table_remove_all(maps->metadata_maps);
621 }
622 }
623
624 BT_HIDDEN
625 void trace_ir_maps_destroy(struct trace_ir_maps *maps)
626 {
627 if (!maps) {
628 return;
629 }
630
631 if (maps->debug_info_field_class_name) {
632 g_free(maps->debug_info_field_class_name);
633 }
634
635 if (maps->data_maps) {
636 g_hash_table_destroy(maps->data_maps);
637 maps->data_maps = NULL;
638 }
639
640 if (maps->metadata_maps) {
641 g_hash_table_destroy(maps->metadata_maps);
642 maps->metadata_maps = NULL;
643 }
644
645 g_free(maps);
646 }
647
648 BT_HIDDEN
649 struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp,
650 const char *debug_info_field_name)
651 {
652 struct trace_ir_maps *trace_ir_maps =
653 g_new0(struct trace_ir_maps, 1);
654 if (!trace_ir_maps) {
655 BT_LOGE_STR("Error allocating trace_ir_maps");
656 goto error;
657 }
658
659 /* Copy debug info field name received from the user. */
660 trace_ir_maps->debug_info_field_class_name =
661 g_strdup(debug_info_field_name);
662 if (!trace_ir_maps->debug_info_field_class_name) {
663 BT_LOGE_STR("Cannot copy debug info field name");
664 goto error;
665 }
666
667 trace_ir_maps->self_comp = self_comp;
668
669 trace_ir_maps->data_maps = g_hash_table_new_full(g_direct_hash,
670 g_direct_equal, (GDestroyNotify) NULL,
671 (GDestroyNotify) trace_ir_data_maps_destroy);
672
673 trace_ir_maps->metadata_maps = g_hash_table_new_full(g_direct_hash,
674 g_direct_equal, (GDestroyNotify) NULL,
675 (GDestroyNotify) trace_ir_metadata_maps_destroy);
676
677 goto end;
678 error:
679 trace_ir_maps_destroy(trace_ir_maps);
680 trace_ir_maps = NULL;
681 end:
682 return trace_ir_maps;
683 }
This page took 0.041794 seconds and 3 git commands to generate.