lib/plugin/plugin-so.c: add logging
[babeltrace.git] / lib / plugin / plugin-so.c
1 /*
2 * plugin-so.c
3 *
4 * Babeltrace Plugin (shared object)
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #define BT_LOG_TAG "PLUGIN-SO"
31 #include <babeltrace/lib-logging-internal.h>
32
33 #include <babeltrace/compiler-internal.h>
34 #include <babeltrace/ref.h>
35 #include <babeltrace/plugin/plugin-internal.h>
36 #include <babeltrace/plugin/plugin-so-internal.h>
37 #include <babeltrace/plugin/plugin-dev.h>
38 #include <babeltrace/plugin/plugin-internal.h>
39 #include <babeltrace/graph/component-class-internal.h>
40 #include <babeltrace/types.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <glib.h>
44 #include <gmodule.h>
45
46 #define NATIVE_PLUGIN_SUFFIX ".so"
47 #define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
48 #define LIBTOOL_PLUGIN_SUFFIX ".la"
49 #define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
50
51 #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
52 sizeof(LIBTOOL_PLUGIN_SUFFIX))
53
54 #define SECTION_BEGIN(_name) (&(__start_##_name))
55 #define SECTION_END(_name) (&(__stop_##_name))
56 #define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
57
58 #define DECLARE_SECTION(_type, _name) \
59 extern _type __start_##_name __attribute((weak)); \
60 extern _type __stop_##_name __attribute((weak))
61
62 DECLARE_SECTION(struct __bt_plugin_descriptor const *, __bt_plugin_descriptors);
63 DECLARE_SECTION(struct __bt_plugin_descriptor_attribute const *, __bt_plugin_descriptor_attributes);
64 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor const *, __bt_plugin_component_class_descriptors);
65 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute const *, __bt_plugin_component_class_descriptor_attributes);
66
67 /*
68 * This hash table, global to the library, maps component class pointers
69 * to shared library handles.
70 *
71 * The keys (component classes) are NOT owned by this hash table, whereas
72 * the values (shared library handles) are owned by this hash table.
73 *
74 * The keys are the component classes created with
75 * bt_plugin_add_component_class(). They keep the shared library handle
76 * object created by their plugin alive so that the plugin's code is
77 * not discarded when it could still be in use by living components
78 * created from those component classes:
79 *
80 * [component] --ref-> [component class] --through this HT-> [shlib handle]
81 *
82 * This hash table exists for two reasons:
83 *
84 * 1. To allow this application:
85 *
86 * my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
87 * // instantiate components from a plugin's component classes
88 * // put plugins and free my_plugins here
89 * // user code of instantiated components still exists
90 *
91 * 2. To decouple the plugin subsystem from the component subsystem:
92 * while plugins objects need to know component class objects, the
93 * opposite is not necessary, thus it makes no sense for a component
94 * class to keep a reference to the plugin object from which it was
95 * created.
96 *
97 * An entry is removed from this HT when a component class is destroyed
98 * thanks to a custom destroy listener. When the entry is removed, the
99 * GLib function calls the value destroy notifier of the HT, which is
100 * bt_put(). This decreases the reference count of the mapped shared
101 * library handle. Assuming the original plugin object which contained
102 * some component classes is put first, when the last component class is
103 * removed from this HT, the shared library handle object's reference
104 * count falls to zero and the shared library is finally closed.
105 */
106 static
107 GHashTable *comp_classes_to_shlib_handles;
108
109 __attribute__((constructor)) static
110 void init_comp_classes_to_shlib_handles(void) {
111 comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash,
112 g_direct_equal, NULL, bt_put);
113 assert(comp_classes_to_shlib_handles);
114 BT_LOGD_STR("Initialized component class to shared library handle hash table.");
115 }
116
117 __attribute__((destructor)) static
118 void fini_comp_classes_to_shlib_handles(void) {
119 if (comp_classes_to_shlib_handles) {
120 g_hash_table_destroy(comp_classes_to_shlib_handles);
121 BT_LOGD_STR("Destroyed component class to shared library handle hash table.");
122 }
123 }
124
125 static
126 void bt_plugin_so_shared_lib_handle_destroy(struct bt_object *obj)
127 {
128 struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
129
130 assert(obj);
131 shared_lib_handle = container_of(obj,
132 struct bt_plugin_so_shared_lib_handle, base);
133 const char *path = shared_lib_handle->path ?
134 shared_lib_handle->path->str : NULL;
135
136 BT_LOGD("Destroying shared library handle: addr=%p, path=\"%s\"",
137 shared_lib_handle, path);
138
139 if (shared_lib_handle->init_called && shared_lib_handle->exit) {
140 enum bt_plugin_status status;
141
142 BT_LOGD_STR("Calling user's plugin exit function.");
143 status = shared_lib_handle->exit();
144 BT_LOGD("User function returned: %s",
145 bt_plugin_status_string(status));
146
147 if (status < 0) {
148 BT_LOGW("User's plugin exit function failed: "
149 "path=\"%s\"", path);
150 }
151 }
152
153 if (shared_lib_handle->module) {
154 #ifndef NDEBUG
155 /*
156 * Valgrind shows incomplete stack traces when
157 * dynamically loaded libraries are closed before it
158 * finishes. Use the BABELTRACE_NO_DLCLOSE in a debug
159 * build to avoid this.
160 */
161 const char *var = getenv("BABELTRACE_NO_DLCLOSE");
162
163 if (!var || strcmp(var, "1") != 0) {
164 #endif
165 BT_LOGD("Closing GModule: path=\"%s\"", path);
166
167 if (!g_module_close(shared_lib_handle->module)) {
168 BT_LOGE("Cannot close GModule: %s: path=\"%s\"",
169 g_module_error(), path);
170 }
171 #ifndef NDEBUG
172 } else {
173 BT_LOGD("Not closing GModule because `BABELTRACE_NO_DLCLOSE=1`: "
174 "path=\"%s\"", path);
175 }
176 #endif
177 }
178
179 if (shared_lib_handle->path) {
180 g_string_free(shared_lib_handle->path, TRUE);
181 }
182
183 g_free(shared_lib_handle);
184 }
185
186 static
187 struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create(
188 const char *path)
189 {
190 struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
191
192 BT_LOGD("Creating shared library handle: path=\"%s\"", path);
193 shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1);
194 if (!shared_lib_handle) {
195 BT_LOGE_STR("Failed to allocate one shared library handle.");
196 goto error;
197 }
198
199 bt_object_init(shared_lib_handle, bt_plugin_so_shared_lib_handle_destroy);
200
201 if (!path) {
202 goto end;
203 }
204
205 shared_lib_handle->path = g_string_new(path);
206 if (!shared_lib_handle->path) {
207 BT_LOGE_STR("Failed to allocate a GString.");
208 goto error;
209 }
210
211 shared_lib_handle->module = g_module_open(path, 0);
212 if (!shared_lib_handle->module) {
213 BT_LOGW("Cannot open GModule: %s: path=\"%s\"",
214 g_module_error(), path);
215 goto error;
216 }
217
218 goto end;
219
220 error:
221 BT_PUT(shared_lib_handle);
222
223 end:
224 if (shared_lib_handle) {
225 BT_LOGD("Created shared library handle: path=\"%s\", addr=%p",
226 path, shared_lib_handle);
227 }
228
229 return shared_lib_handle;
230 }
231
232 static
233 void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin)
234 {
235 struct bt_plugin_so_spec_data *spec = plugin->spec_data;
236
237 if (!plugin->spec_data) {
238 return;
239 }
240
241 assert(plugin->type == BT_PLUGIN_TYPE_SO);
242 assert(spec);
243 BT_PUT(spec->shared_lib_handle);
244 g_free(plugin->spec_data);
245 plugin->spec_data = NULL;
246 }
247
248 /*
249 * This function does the following:
250 *
251 * 1. Iterate on the plugin descriptor attributes section and set the
252 * plugin's attributes depending on the attribute types. This
253 * includes the name of the plugin, its description, and its
254 * initialization function, for example.
255 *
256 * 2. Iterate on the component class descriptors section and create one
257 * "full descriptor" (temporary structure) for each one that is found
258 * and attached to our plugin descriptor.
259 *
260 * 3. Iterate on the component class descriptor attributes section and
261 * set the corresponding full descriptor's attributes depending on
262 * the attribute types. This includes the description of the
263 * component class, as well as its initialization and destroy
264 * methods.
265 *
266 * 4. Call the user's plugin initialization function, if any is
267 * defined.
268 *
269 * 5. For each full component class descriptor, create a component class
270 * object, set its optional attributes, and add it to the plugin
271 * object.
272 *
273 * 6. Freeze the plugin object.
274 */
275 static
276 enum bt_plugin_status bt_plugin_so_init(
277 struct bt_plugin *plugin,
278 const struct __bt_plugin_descriptor *descriptor,
279 struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
280 struct __bt_plugin_descriptor_attribute const * const *attrs_end,
281 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
282 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
283 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
284 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
285 {
286 /*
287 * This structure's members point to the plugin's memory
288 * (do NOT free).
289 */
290 struct comp_class_full_descriptor {
291 const struct __bt_plugin_component_class_descriptor *descriptor;
292 const char *description;
293 const char *help;
294 bt_component_class_init_method init_method;
295 bt_component_class_finalize_method finalize_method;
296 bt_component_class_query_method query_method;
297 bt_component_class_accept_port_connection_method accept_port_connection_method;
298 bt_component_class_port_connected_method port_connected_method;
299 bt_component_class_port_disconnected_method port_disconnected_method;
300 struct bt_component_class_iterator_methods iterator_methods;
301 };
302
303 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
304 struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
305 struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
306 struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
307 struct bt_plugin_so_spec_data *spec = plugin->spec_data;
308 GArray *comp_class_full_descriptors;
309 size_t i;
310 int ret;
311
312 BT_LOGD("Initializing plugin object from descriptors found in sections: "
313 "plugin-addr=%p, plugin-path=\"%s\", "
314 "attrs-begin-addr=%p, attrs-end-addr=%p, "
315 "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
316 "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p",
317 plugin,
318 spec->shared_lib_handle->path ?
319 spec->shared_lib_handle->path->str : NULL,
320 attrs_begin, attrs_end,
321 cc_descriptors_begin, cc_descriptors_end,
322 cc_descr_attrs_begin, cc_descr_attrs_end);
323 comp_class_full_descriptors = g_array_new(FALSE, TRUE,
324 sizeof(struct comp_class_full_descriptor));
325 if (!comp_class_full_descriptors) {
326 BT_LOGE_STR("Failed to allocate a GArray.");
327 status = BT_PLUGIN_STATUS_ERROR;
328 goto end;
329 }
330
331 /* Set mandatory attributes */
332 spec->descriptor = descriptor;
333 bt_plugin_set_name(plugin, descriptor->name);
334
335 /*
336 * Find and set optional attributes attached to this plugin
337 * descriptor.
338 */
339 for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
340 const struct __bt_plugin_descriptor_attribute *cur_attr =
341 *cur_attr_ptr;
342
343 if (cur_attr->plugin_descriptor != descriptor) {
344 continue;
345 }
346
347 switch (cur_attr->type) {
348 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
349 spec->init = cur_attr->value.init;
350 break;
351 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
352 spec->shared_lib_handle->exit = cur_attr->value.exit;
353 break;
354 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
355 bt_plugin_set_author(plugin, cur_attr->value.author);
356 break;
357 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
358 bt_plugin_set_license(plugin, cur_attr->value.license);
359 break;
360 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
361 bt_plugin_set_description(plugin, cur_attr->value.description);
362 break;
363 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
364 bt_plugin_set_version(plugin,
365 (unsigned int) cur_attr->value.version.major,
366 (unsigned int) cur_attr->value.version.minor,
367 (unsigned int) cur_attr->value.version.patch,
368 cur_attr->value.version.extra);
369 break;
370 default:
371 BT_LOGW("Ignoring unknown plugin descriptor attribute: "
372 "plugin-path=\"%s\", plugin-name=\"%s\", "
373 "attr-type-name=\"%s\", attr-type-id=%d",
374 spec->shared_lib_handle->path ?
375 spec->shared_lib_handle->path->str :
376 NULL,
377 descriptor->name, cur_attr->type_name,
378 cur_attr->type);
379 break;
380 }
381 }
382
383 /*
384 * Find component class descriptors attached to this plugin
385 * descriptor and initialize corresponding full component class
386 * descriptors in the array.
387 */
388 for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
389 const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
390 *cur_cc_descr_ptr;
391 struct comp_class_full_descriptor full_descriptor = {0};
392
393 if (cur_cc_descr->plugin_descriptor != descriptor) {
394 continue;
395 }
396
397 full_descriptor.descriptor = cur_cc_descr;
398 g_array_append_val(comp_class_full_descriptors,
399 full_descriptor);
400 }
401
402 /*
403 * Find component class descriptor attributes attached to this
404 * plugin descriptor and update corresponding full component
405 * class descriptors in the array.
406 */
407 for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
408 const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
409 *cur_cc_descr_attr_ptr;
410
411 if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
412 descriptor) {
413 continue;
414 }
415
416 /* Find the corresponding component class descriptor entry */
417 for (i = 0; i < comp_class_full_descriptors->len; i++) {
418 struct comp_class_full_descriptor *cc_full_descr =
419 &g_array_index(comp_class_full_descriptors,
420 struct comp_class_full_descriptor, i);
421
422 if (cur_cc_descr_attr->comp_class_descriptor ==
423 cc_full_descr->descriptor) {
424 switch (cur_cc_descr_attr->type) {
425 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
426 cc_full_descr->description =
427 cur_cc_descr_attr->value.description;
428 break;
429 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_HELP:
430 cc_full_descr->help =
431 cur_cc_descr_attr->value.help;
432 break;
433 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
434 cc_full_descr->init_method =
435 cur_cc_descr_attr->value.init_method;
436 break;
437 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FINALIZE_METHOD:
438 cc_full_descr->finalize_method =
439 cur_cc_descr_attr->value.finalize_method;
440 break;
441 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_QUERY_METHOD:
442 cc_full_descr->query_method =
443 cur_cc_descr_attr->value.query_method;
444 break;
445 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_PORT_CONNECTION_METHOD:
446 cc_full_descr->accept_port_connection_method =
447 cur_cc_descr_attr->value.accept_port_connection_method;
448 break;
449 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_PORT_CONNECTED_METHOD:
450 cc_full_descr->port_connected_method =
451 cur_cc_descr_attr->value.port_connected_method;
452 break;
453 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_PORT_DISCONNECTED_METHOD:
454 cc_full_descr->port_disconnected_method =
455 cur_cc_descr_attr->value.port_disconnected_method;
456 break;
457 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD:
458 cc_full_descr->iterator_methods.init =
459 cur_cc_descr_attr->value.notif_iter_init_method;
460 break;
461 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_FINALIZE_METHOD:
462 cc_full_descr->iterator_methods.finalize =
463 cur_cc_descr_attr->value.notif_iter_finalize_method;
464 break;
465 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD:
466 cc_full_descr->iterator_methods.seek_time =
467 cur_cc_descr_attr->value.notif_iter_seek_time_method;
468 break;
469 default:
470 BT_LOGW("Ignoring unknown component class descriptor attribute: "
471 "plugin-path=\"%s\", "
472 "plugin-name=\"%s\", "
473 "comp-class-name=\"%s\", "
474 "comp-class-type=%s, "
475 "attr-type-name=\"%s\", "
476 "attr-type-id=%d",
477 spec->shared_lib_handle->path ?
478 spec->shared_lib_handle->path->str :
479 NULL,
480 descriptor->name,
481 cur_cc_descr_attr->comp_class_descriptor->name,
482 bt_component_class_type_string(
483 cur_cc_descr_attr->comp_class_descriptor->type),
484 cur_cc_descr_attr->type_name,
485 cur_cc_descr_attr->type);
486 break;
487 }
488 }
489 }
490 }
491
492 /* Initialize plugin */
493 if (spec->init) {
494 BT_LOGD_STR("Calling user's plugin initialization function.");
495 status = spec->init(plugin);
496 BT_LOGD("User function returned: %s",
497 bt_plugin_status_string(status));
498
499 if (status < 0) {
500 BT_LOGW_STR("User's plugin initialization function failed.");
501 goto end;
502 }
503 }
504
505 spec->shared_lib_handle->init_called = BT_TRUE;
506
507 /* Add described component classes to plugin */
508 for (i = 0; i < comp_class_full_descriptors->len; i++) {
509 struct comp_class_full_descriptor *cc_full_descr =
510 &g_array_index(comp_class_full_descriptors,
511 struct comp_class_full_descriptor, i);
512 struct bt_component_class *comp_class;
513
514 BT_LOGD("Creating and setting properties of plugin's component class: "
515 "plugin-path=\"%s\", plugin-name=\"%s\", "
516 "comp-class-name=\"%s\", comp-class-type=%s",
517 spec->shared_lib_handle->path ?
518 spec->shared_lib_handle->path->str :
519 NULL,
520 descriptor->name,
521 cc_full_descr->descriptor->name,
522 bt_component_class_type_string(
523 cc_full_descr->descriptor->type));
524
525 switch (cc_full_descr->descriptor->type) {
526 case BT_COMPONENT_CLASS_TYPE_SOURCE:
527 comp_class = bt_component_class_source_create(
528 cc_full_descr->descriptor->name,
529 cc_full_descr->descriptor->methods.source.notif_iter_next);
530 break;
531 case BT_COMPONENT_CLASS_TYPE_FILTER:
532 comp_class = bt_component_class_filter_create(
533 cc_full_descr->descriptor->name,
534 cc_full_descr->descriptor->methods.source.notif_iter_next);
535 break;
536 case BT_COMPONENT_CLASS_TYPE_SINK:
537 comp_class = bt_component_class_sink_create(
538 cc_full_descr->descriptor->name,
539 cc_full_descr->descriptor->methods.sink.consume);
540 break;
541 default:
542 BT_LOGW("Ignoring unknown component class type: "
543 "plugin-path=\"%s\", plugin-name=\"%s\", "
544 "comp-class-name=\"%s\", comp-class-type=%d",
545 spec->shared_lib_handle->path->str ?
546 spec->shared_lib_handle->path->str :
547 NULL,
548 descriptor->name,
549 cc_full_descr->descriptor->name,
550 cc_full_descr->descriptor->type);
551 continue;
552 }
553
554 if (!comp_class) {
555 BT_LOGE_STR("Cannot create component class.");
556 status = BT_PLUGIN_STATUS_ERROR;
557 goto end;
558 }
559
560 if (cc_full_descr->description) {
561 ret = bt_component_class_set_description(comp_class,
562 cc_full_descr->description);
563 if (ret) {
564 BT_LOGE_STR("Cannot set component class's description.");
565 status = BT_PLUGIN_STATUS_ERROR;
566 BT_PUT(comp_class);
567 goto end;
568 }
569 }
570
571 if (cc_full_descr->help) {
572 ret = bt_component_class_set_help(comp_class,
573 cc_full_descr->help);
574 if (ret) {
575 BT_LOGE_STR("Cannot set component class's help string.");
576 status = BT_PLUGIN_STATUS_ERROR;
577 BT_PUT(comp_class);
578 goto end;
579 }
580 }
581
582 if (cc_full_descr->init_method) {
583 ret = bt_component_class_set_init_method(comp_class,
584 cc_full_descr->init_method);
585 if (ret) {
586 BT_LOGE_STR("Cannot set component class's initialization method.");
587 status = BT_PLUGIN_STATUS_ERROR;
588 BT_PUT(comp_class);
589 goto end;
590 }
591 }
592
593 if (cc_full_descr->finalize_method) {
594 ret = bt_component_class_set_finalize_method(comp_class,
595 cc_full_descr->finalize_method);
596 if (ret) {
597 BT_LOGE_STR("Cannot set component class's finalization method.");
598 status = BT_PLUGIN_STATUS_ERROR;
599 BT_PUT(comp_class);
600 goto end;
601 }
602 }
603
604 if (cc_full_descr->query_method) {
605 ret = bt_component_class_set_query_method(
606 comp_class, cc_full_descr->query_method);
607 if (ret) {
608 BT_LOGE_STR("Cannot set component class's query method.");
609 status = BT_PLUGIN_STATUS_ERROR;
610 BT_PUT(comp_class);
611 goto end;
612 }
613 }
614
615 if (cc_full_descr->accept_port_connection_method) {
616 ret = bt_component_class_set_accept_port_connection_method(
617 comp_class, cc_full_descr->accept_port_connection_method);
618 if (ret) {
619 BT_LOGE_STR("Cannot set component class's \"accept port connection\" method.");
620 status = BT_PLUGIN_STATUS_ERROR;
621 BT_PUT(comp_class);
622 goto end;
623 }
624 }
625
626 if (cc_full_descr->port_connected_method) {
627 ret = bt_component_class_set_port_connected_method(
628 comp_class, cc_full_descr->port_connected_method);
629 if (ret) {
630 BT_LOGE_STR("Cannot set component class's \"port connected\" method.");
631 status = BT_PLUGIN_STATUS_ERROR;
632 BT_PUT(comp_class);
633 goto end;
634 }
635 }
636
637 if (cc_full_descr->port_disconnected_method) {
638 ret = bt_component_class_set_port_disconnected_method(
639 comp_class, cc_full_descr->port_disconnected_method);
640 if (ret) {
641 BT_LOGE_STR("Cannot set component class's \"port disconnected\" method.");
642 status = BT_PLUGIN_STATUS_ERROR;
643 BT_PUT(comp_class);
644 goto end;
645 }
646 }
647
648 switch (cc_full_descr->descriptor->type) {
649 case BT_COMPONENT_CLASS_TYPE_SOURCE:
650 if (cc_full_descr->iterator_methods.init) {
651 ret = bt_component_class_source_set_notification_iterator_init_method(
652 comp_class,
653 cc_full_descr->iterator_methods.init);
654 if (ret) {
655 BT_LOGE_STR("Cannot set component class's notification iterator initialization method.");
656 status = BT_PLUGIN_STATUS_ERROR;
657 BT_PUT(comp_class);
658 goto end;
659 }
660 }
661
662 if (cc_full_descr->iterator_methods.finalize) {
663 ret = bt_component_class_source_set_notification_iterator_finalize_method(
664 comp_class,
665 cc_full_descr->iterator_methods.finalize);
666 if (ret) {
667 BT_LOGE_STR("Cannot set source component class's notification iterator finalization method.");
668 status = BT_PLUGIN_STATUS_ERROR;
669 BT_PUT(comp_class);
670 goto end;
671 }
672 }
673
674 if (cc_full_descr->iterator_methods.seek_time) {
675 ret = bt_component_class_source_set_notification_iterator_seek_time_method(
676 comp_class,
677 cc_full_descr->iterator_methods.seek_time);
678 if (ret) {
679 BT_LOGE_STR("Cannot set source component class's notification iterator seek to time method.");
680 status = BT_PLUGIN_STATUS_ERROR;
681 BT_PUT(comp_class);
682 goto end;
683 }
684 }
685 break;
686 case BT_COMPONENT_CLASS_TYPE_FILTER:
687 if (cc_full_descr->iterator_methods.init) {
688 ret = bt_component_class_filter_set_notification_iterator_init_method(
689 comp_class,
690 cc_full_descr->iterator_methods.init);
691 if (ret) {
692 BT_LOGE_STR("Cannot set filter component class's notification iterator initialization method.");
693 status = BT_PLUGIN_STATUS_ERROR;
694 BT_PUT(comp_class);
695 goto end;
696 }
697 }
698
699 if (cc_full_descr->iterator_methods.finalize) {
700 ret = bt_component_class_filter_set_notification_iterator_finalize_method(
701 comp_class,
702 cc_full_descr->iterator_methods.finalize);
703 if (ret) {
704 BT_LOGE_STR("Cannot set filter component class's notification iterator finalization method.");
705 status = BT_PLUGIN_STATUS_ERROR;
706 BT_PUT(comp_class);
707 goto end;
708 }
709 }
710
711 if (cc_full_descr->iterator_methods.seek_time) {
712 ret = bt_component_class_filter_set_notification_iterator_seek_time_method(
713 comp_class,
714 cc_full_descr->iterator_methods.seek_time);
715 if (ret) {
716 BT_LOGE_STR("Cannot set filter component class's notification iterator seek to time method.");
717 status = BT_PLUGIN_STATUS_ERROR;
718 BT_PUT(comp_class);
719 goto end;
720 }
721 }
722 break;
723 case BT_COMPONENT_CLASS_TYPE_SINK:
724 break;
725 default:
726 abort();
727 }
728
729 /*
730 * Add component class to the plugin object.
731 *
732 * This will call back
733 * bt_plugin_so_on_add_component_class() so that we can
734 * add a mapping in comp_classes_to_shlib_handles when
735 * we know the component class is successfully added.
736 */
737 status = bt_plugin_add_component_class(plugin,
738 comp_class);
739 BT_PUT(comp_class);
740 if (status < 0) {
741 BT_LOGE("Cannot add component class to plugin.");
742 goto end;
743 }
744 }
745
746 /*
747 * All the plugin's component classes should be added at this
748 * point. We freeze the plugin so that it's not possible to add
749 * component classes to this plugin object after this stage
750 * (plugin object becomes immutable).
751 */
752 bt_plugin_freeze(plugin);
753
754 end:
755 g_array_free(comp_class_full_descriptors, TRUE);
756 return status;
757 }
758
759 static
760 struct bt_plugin *bt_plugin_so_create_empty(
761 struct bt_plugin_so_shared_lib_handle *shared_lib_handle)
762 {
763 struct bt_plugin *plugin;
764 struct bt_plugin_so_spec_data *spec;
765
766 plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_SO);
767 if (!plugin) {
768 goto error;
769 }
770
771 plugin->destroy_spec_data = bt_plugin_so_destroy_spec_data;
772 plugin->spec_data = g_new0(struct bt_plugin_so_spec_data, 1);
773 if (!plugin->spec_data) {
774 BT_LOGE_STR("Failed to allocate one SO plugin specific data structure.");
775 goto error;
776 }
777
778 spec = plugin->spec_data;
779 spec->shared_lib_handle = bt_get(shared_lib_handle);
780 goto end;
781
782 error:
783 BT_PUT(plugin);
784
785 end:
786 return plugin;
787 }
788
789 static
790 struct bt_plugin_set *bt_plugin_so_create_all_from_sections(
791 struct bt_plugin_so_shared_lib_handle *shared_lib_handle,
792 struct __bt_plugin_descriptor const * const *descriptors_begin,
793 struct __bt_plugin_descriptor const * const *descriptors_end,
794 struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
795 struct __bt_plugin_descriptor_attribute const * const *attrs_end,
796 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
797 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
798 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
799 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
800 {
801 size_t descriptor_count;
802 size_t attrs_count;
803 size_t cc_descriptors_count;
804 size_t cc_descr_attrs_count;
805 size_t i;
806 struct bt_plugin_set *plugin_set = NULL;
807
808 descriptor_count = descriptors_end - descriptors_begin;
809 attrs_count = attrs_end - attrs_begin;
810 cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin;
811 cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin;
812
813 BT_LOGD("Creating all SO plugins from sections: "
814 "plugin-path=\"%s\", "
815 "descr-begin-addr=%p, descr-end-addr=%p, "
816 "attrs-begin-addr=%p, attrs-end-addr=%p, "
817 "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
818 "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p, "
819 "descr-count=%zu, attrs-count=%zu, "
820 "cc-descr-count=%zu, cc-descr-attrs-count=%zu",
821 shared_lib_handle->path ? shared_lib_handle->path->str : NULL,
822 descriptors_begin, descriptors_end,
823 attrs_begin, attrs_end,
824 cc_descriptors_begin, cc_descriptors_end,
825 cc_descr_attrs_begin, cc_descr_attrs_end,
826 descriptor_count, attrs_count,
827 cc_descriptors_count, cc_descr_attrs_count);
828 plugin_set = bt_plugin_set_create();
829 if (!plugin_set) {
830 BT_LOGE_STR("Cannot create empty plugin set.");
831 goto error;
832 }
833
834 for (i = 0; i < descriptor_count; i++) {
835 enum bt_plugin_status status;
836 const struct __bt_plugin_descriptor *descriptor =
837 descriptors_begin[i];
838 struct bt_plugin *plugin;
839
840 BT_LOGD("Creating plugin object for plugin: "
841 "name=\"%s\", abi-major=%d, abi-minor=%d",
842 descriptor->name, descriptor->major, descriptor->minor);
843
844 if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
845 BT_LOGW("Unknown ABI major version: abi-major=%d",
846 descriptor->major);
847 goto error;
848 }
849
850 plugin = bt_plugin_so_create_empty(shared_lib_handle);
851 if (!plugin) {
852 BT_LOGE_STR("Cannot create empty shared library handle.");
853 goto error;
854 }
855
856 if (shared_lib_handle && shared_lib_handle->path) {
857 bt_plugin_set_path(plugin, shared_lib_handle->path->str);
858 }
859
860 status = bt_plugin_so_init(plugin, descriptor, attrs_begin,
861 attrs_end, cc_descriptors_begin, cc_descriptors_end,
862 cc_descr_attrs_begin, cc_descr_attrs_end);
863 if (status < 0) {
864 BT_LOGW_STR("Cannot initialize SO plugin object from sections.");
865 BT_PUT(plugin);
866 goto error;
867 }
868
869 /* Add to plugin set */
870 bt_plugin_set_add_plugin(plugin_set, plugin);
871 bt_put(plugin);
872 }
873
874 goto end;
875
876 error:
877 BT_PUT(plugin_set);
878
879 end:
880 return plugin_set;
881 }
882
883 BT_HIDDEN
884 struct bt_plugin_set *bt_plugin_so_create_all_from_static(void)
885 {
886 struct bt_plugin_set *plugin_set = NULL;
887 struct bt_plugin_so_shared_lib_handle *shared_lib_handle =
888 bt_plugin_so_shared_lib_handle_create(NULL);
889
890 if (!shared_lib_handle) {
891 goto end;
892 }
893
894 BT_LOGD_STR("Creating all SO plugins from built-in plugins.");
895 plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
896 SECTION_BEGIN(__bt_plugin_descriptors),
897 SECTION_END(__bt_plugin_descriptors),
898 SECTION_BEGIN(__bt_plugin_descriptor_attributes),
899 SECTION_END(__bt_plugin_descriptor_attributes),
900 SECTION_BEGIN(__bt_plugin_component_class_descriptors),
901 SECTION_END(__bt_plugin_component_class_descriptors),
902 SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes),
903 SECTION_END(__bt_plugin_component_class_descriptor_attributes));
904
905 end:
906 BT_PUT(shared_lib_handle);
907
908 return plugin_set;
909 }
910
911 BT_HIDDEN
912 struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path)
913 {
914 size_t path_len;
915 struct bt_plugin_set *plugin_set = NULL;
916 struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
917 struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
918 struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
919 struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
920 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
921 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
922 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
923 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
924 bt_bool is_libtool_wrapper = BT_FALSE, is_shared_object = BT_FALSE;
925 struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
926
927 if (!path) {
928 BT_LOGW_STR("Invalid parameter: path is NULL.");
929 goto end;
930 }
931
932 BT_LOGD("Creating all SO plugins from file: path=\"%s\"", path);
933 path_len = strlen(path);
934 if (path_len <= PLUGIN_SUFFIX_LEN) {
935 BT_LOGW("Invalid parameter: path length is too short: "
936 "path-length=%zu", path_len);
937 goto end;
938 }
939
940 path_len++;
941 /*
942 * Check if the file ends with a known plugin file type suffix (i.e. .so
943 * or .la on Linux).
944 */
945 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
946 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
947 LIBTOOL_PLUGIN_SUFFIX_LEN);
948 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
949 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
950 NATIVE_PLUGIN_SUFFIX_LEN);
951 if (!is_shared_object && !is_libtool_wrapper) {
952 /* Name indicates this is not a plugin file; not an error */
953 BT_LOGV("File is not a SO plugin file: path=\"%s\"", path);
954 goto end;
955 }
956
957 shared_lib_handle = bt_plugin_so_shared_lib_handle_create(path);
958 if (!shared_lib_handle) {
959 BT_LOGW_STR("Cannot create shared library handle.");
960 goto end;
961 }
962
963 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors",
964 (gpointer *) &descriptors_begin)) {
965 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
966 "symbol=\"%s\"", path,
967 "__start___bt_plugin_descriptors");
968 goto end;
969 }
970
971 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors",
972 (gpointer *) &descriptors_end)) {
973 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
974 "symbol=\"%s\"", path,
975 "__stop___bt_plugin_descriptors");
976 goto end;
977 }
978
979 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes",
980 (gpointer *) &attrs_begin)) {
981 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
982 "symbol=\"%s\"", path,
983 "__start___bt_plugin_descriptor_attributes");
984 }
985
986 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes",
987 (gpointer *) &attrs_end)) {
988 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
989 "symbol=\"%s\"", path,
990 "__stop___bt_plugin_descriptor_attributes");
991 }
992
993 if ((!!attrs_begin - !!attrs_end) != 0) {
994 BT_LOGD("Found section start or end symbol, but not both: "
995 "path=\"%s\", symbol-start=\"%s\", "
996 "symbol-end=\"%s\", symbol-start-addr=%p, "
997 "symbol-end-addr=%p",
998 path, "__start___bt_plugin_descriptor_attributes",
999 "__stop___bt_plugin_descriptor_attributes",
1000 attrs_begin, attrs_end);
1001 goto end;
1002 }
1003
1004 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors",
1005 (gpointer *) &cc_descriptors_begin)) {
1006 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1007 "symbol=\"%s\"", path,
1008 "__start___bt_plugin_component_class_descriptors");
1009 }
1010
1011 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors",
1012 (gpointer *) &cc_descriptors_end)) {
1013 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1014 "symbol=\"%s\"", path,
1015 "__stop___bt_plugin_component_class_descriptors");
1016 }
1017
1018 if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
1019 BT_LOGD("Found section start or end symbol, but not both: "
1020 "path=\"%s\", symbol-start=\"%s\", "
1021 "symbol-end=\"%s\", symbol-start-addr=%p, "
1022 "symbol-end-addr=%p",
1023 path, "__start___bt_plugin_component_class_descriptors",
1024 "__stop___bt_plugin_component_class_descriptors",
1025 cc_descriptors_begin, cc_descriptors_end);
1026 goto end;
1027 }
1028
1029 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes",
1030 (gpointer *) &cc_descr_attrs_begin)) {
1031 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1032 "symbol=\"%s\"", path,
1033 "__start___bt_plugin_component_class_descriptor_attributes");
1034 }
1035
1036 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes",
1037 (gpointer *) &cc_descr_attrs_end)) {
1038 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1039 "symbol=\"%s\"", path,
1040 "__stop___bt_plugin_component_class_descriptor_attributes");
1041 }
1042
1043 if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
1044 BT_LOGD("Found section start or end symbol, but not both: "
1045 "path=\"%s\", symbol-start=\"%s\", "
1046 "symbol-end=\"%s\", symbol-start-addr=%p, "
1047 "symbol-end-addr=%p",
1048 path, "__start___bt_plugin_component_class_descriptor_attributes",
1049 "__stop___bt_plugin_component_class_descriptor_attributes",
1050 cc_descr_attrs_begin, cc_descr_attrs_end);
1051 goto end;
1052 }
1053
1054 /* Initialize plugin */
1055 BT_LOGD_STR("Initializing plugin object.");
1056 plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
1057 descriptors_begin, descriptors_end, attrs_begin, attrs_end,
1058 cc_descriptors_begin, cc_descriptors_end,
1059 cc_descr_attrs_begin, cc_descr_attrs_end);
1060
1061 end:
1062 BT_PUT(shared_lib_handle);
1063 return plugin_set;
1064 }
1065
1066 static
1067 void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
1068 void *data)
1069 {
1070 gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
1071 comp_class);
1072 assert(exists);
1073 BT_LOGV("Component class destroyed: removed entry from hash table: "
1074 "comp-cls-addr=%p", comp_class);
1075 }
1076
1077 BT_HIDDEN
1078 void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
1079 struct bt_component_class *comp_class)
1080 {
1081 struct bt_plugin_so_spec_data *spec = plugin->spec_data;
1082
1083 assert(plugin->spec_data);
1084 assert(plugin->type == BT_PLUGIN_TYPE_SO);
1085
1086 /* Map component class pointer to shared lib handle in global HT */
1087 g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
1088 bt_get(spec->shared_lib_handle));
1089
1090 /* Add our custom destroy listener */
1091 bt_component_class_add_destroy_listener(comp_class,
1092 plugin_comp_class_destroy_listener, NULL);
1093 }
This page took 0.050445 seconds and 4 git commands to generate.