+ location->function_name = function_name_copy;
+ location->binary_path = binary_path_copy;
+ location->binary_fd_handle = binary_fd_handle;
+ binary_fd_handle = NULL;
+ location->instrumentation_type =
+ LTTNG_USERSPACE_PROBE_LOCATION_FUNCTION_INSTRUMENTATION_TYPE_ENTRY;
+
+ ret = &location->parent;
+ ret->lookup_method = lookup_method;
+ ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION;
+ ret->equal = lttng_userspace_probe_location_function_is_equal;
+ goto end;
+
+error:
+ free(function_name_copy);
+ free(binary_path_copy);
+ if (binary_fd >= 0) {
+ if (close(binary_fd)) {
+ PERROR("Error closing binary fd in error path");
+ }
+ }
+ fd_handle_put(binary_fd_handle);
+end:
+ return ret;
+}
+
+static bool lttng_userspace_probe_location_tracepoint_is_equal(
+ const struct lttng_userspace_probe_location *_a,
+ const struct lttng_userspace_probe_location *_b)
+{
+ bool is_equal = false;
+ struct lttng_userspace_probe_location_tracepoint *a, *b;
+
+ a = container_of(_a, struct lttng_userspace_probe_location_tracepoint,
+ parent);
+ b = container_of(_b, struct lttng_userspace_probe_location_tracepoint,
+ parent);
+
+ assert(a->probe_name);
+ assert(b->probe_name);
+ if (strcmp(a->probe_name, b->probe_name)) {
+ goto end;
+ }
+
+ assert(a->provider_name);
+ assert(b->provider_name);
+ if (strcmp(a->provider_name, b->provider_name)) {
+ goto end;
+ }
+
+ assert(a->binary_path);
+ assert(b->binary_path);
+ if (strcmp(a->binary_path, b->binary_path)) {
+ goto end;
+ }
+
+ is_equal = fd_is_equal(a->binary_fd_handle ? fd_handle_get_fd(a->binary_fd_handle) : -1,
+ b->binary_fd_handle ? fd_handle_get_fd(b->binary_fd_handle) : -1);
+
+end:
+ return is_equal;
+}
+
+static struct lttng_userspace_probe_location *
+lttng_userspace_probe_location_tracepoint_create_no_check(const char *binary_path,
+ const char *provider_name, const char *probe_name,
+ struct lttng_userspace_probe_location_lookup_method *lookup_method,
+ bool open_binary)
+{
+ int binary_fd = -1;
+ struct fd_handle *binary_fd_handle = NULL;
+ char *probe_name_copy = NULL;
+ char *provider_name_copy = NULL;
+ char *binary_path_copy = NULL;
+ struct lttng_userspace_probe_location *ret = NULL;
+ struct lttng_userspace_probe_location_tracepoint *location;
+
+ if (open_binary) {
+ binary_fd = open(binary_path, O_RDONLY);
+ if (binary_fd < 0) {
+ PERROR("open");
+ goto error;
+ }
+
+ binary_fd_handle = fd_handle_create(binary_fd);
+ if (!binary_fd) {
+ goto error;
+ }
+
+ /* Ownership transferred to fd_handle. */
+ binary_fd = -1;
+ }
+
+ probe_name_copy = lttng_strndup(probe_name, LTTNG_SYMBOL_NAME_LEN);
+ if (!probe_name_copy) {
+ PERROR("lttng_strndup");
+ goto error;
+ }
+
+ provider_name_copy = lttng_strndup(provider_name, LTTNG_SYMBOL_NAME_LEN);
+ if (!provider_name_copy) {
+ PERROR("lttng_strndup");
+ goto error;
+ }
+
+ binary_path_copy = lttng_strndup(binary_path, LTTNG_PATH_MAX);
+ if (!binary_path_copy) {
+ PERROR("lttng_strndup");
+ goto error;
+ }
+
+ location = zmalloc(sizeof(*location));
+ if (!location) {
+ PERROR("zmalloc");
+ goto error;
+ }
+
+ location->probe_name = probe_name_copy;
+ location->provider_name = provider_name_copy;
+ location->binary_path = binary_path_copy;
+ location->binary_fd_handle = binary_fd_handle;
+ binary_fd_handle = NULL;
+
+ ret = &location->parent;
+ ret->lookup_method = lookup_method;
+ ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT;
+ ret->equal = lttng_userspace_probe_location_tracepoint_is_equal;
+ goto end;
+
+error:
+ free(probe_name_copy);
+ free(provider_name_copy);
+ free(binary_path_copy);
+ if (binary_fd >= 0) {
+ if (close(binary_fd)) {
+ PERROR("Error closing binary fd in error path");
+ }
+ }
+ fd_handle_put(binary_fd_handle);
+end:
+ return ret;
+}
+
+struct lttng_userspace_probe_location *
+lttng_userspace_probe_location_function_create(const char *binary_path,
+ const char *function_name,
+ struct lttng_userspace_probe_location_lookup_method *lookup_method)
+{
+ struct lttng_userspace_probe_location *ret = NULL;
+
+ if (!binary_path || !function_name) {
+ ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+ goto end;
+ }
+
+ switch (lttng_userspace_probe_location_lookup_method_get_type(
+ lookup_method)) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+ break;
+ default:
+ /* Invalid probe location lookup method. */
+ goto end;
+ }
+
+ ret = lttng_userspace_probe_location_function_create_no_check(
+ binary_path, function_name, lookup_method, true);
+end:
+ return ret;
+}
+
+struct lttng_userspace_probe_location *
+lttng_userspace_probe_location_tracepoint_create(const char *binary_path,
+ const char *provider_name, const char *probe_name,
+ struct lttng_userspace_probe_location_lookup_method *lookup_method)
+{
+ struct lttng_userspace_probe_location *ret = NULL;
+
+ if (!binary_path || !probe_name || !provider_name) {
+ ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+ goto end;
+ }
+
+ switch (lttng_userspace_probe_location_lookup_method_get_type(
+ lookup_method)) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+ break;
+ default:
+ /* Invalid probe location lookup method. */
+ goto end;
+ }
+
+ ret = lttng_userspace_probe_location_tracepoint_create_no_check(
+ binary_path, provider_name, probe_name, lookup_method, true);
+end:
+ return ret;
+}
+
+static struct lttng_userspace_probe_location_lookup_method *
+lttng_userspace_probe_location_lookup_method_function_elf_copy(
+ const struct lttng_userspace_probe_location_lookup_method *lookup_method)
+{
+ struct lttng_userspace_probe_location_lookup_method *parent = NULL;
+ struct lttng_userspace_probe_location_lookup_method_elf *elf_method;
+
+ assert(lookup_method);
+ assert(lookup_method->type ==
+ LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF);
+
+ elf_method = zmalloc(sizeof(*elf_method));
+ if (!elf_method) {
+ PERROR("Error allocating ELF userspace probe lookup method");
+ goto error;
+ }
+
+ elf_method->parent.type = lookup_method->type;
+ parent = &elf_method->parent;
+
+ goto end;
+error:
+ parent = NULL;
+end:
+ return parent;
+}
+
+static struct lttng_userspace_probe_location_lookup_method *
+lttng_userspace_probe_location_lookup_method_tracepoint_sdt_copy(
+ struct lttng_userspace_probe_location_lookup_method *lookup_method)
+{
+ struct lttng_userspace_probe_location_lookup_method *parent = NULL;
+ struct lttng_userspace_probe_location_lookup_method_sdt *sdt_method;
+
+ assert(lookup_method);
+ assert(lookup_method->type ==
+ LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT);
+
+ sdt_method = zmalloc(sizeof(*sdt_method));
+ if (!sdt_method) {
+ PERROR("zmalloc");
+ goto error;
+ }
+
+ sdt_method->parent.type = lookup_method->type;
+ parent = &sdt_method->parent;
+
+ goto end;
+
+error:
+ parent = NULL;
+end:
+ return parent;
+}
+
+static struct lttng_userspace_probe_location *
+lttng_userspace_probe_location_function_copy(
+ const struct lttng_userspace_probe_location *location)
+{
+ enum lttng_userspace_probe_location_lookup_method_type lookup_type;
+ struct lttng_userspace_probe_location *new_location = NULL;
+ struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
+ const char *binary_path = NULL;
+ const char *function_name = NULL;
+ struct lttng_userspace_probe_location_function *function_location;
+
+ assert(location);
+ assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
+ function_location = container_of(
+ location, typeof(*function_location), parent);
+
+ /* Get probe location fields */
+ binary_path = lttng_userspace_probe_location_function_get_binary_path(location);
+ if (!binary_path) {
+ ERR("Userspace probe binary path is NULL");
+ goto error;
+ }
+
+ function_name = lttng_userspace_probe_location_function_get_function_name(location);
+ if (!function_name) {
+ ERR("Userspace probe function name is NULL");
+ goto error;
+ }
+
+ /*
+ * Duplicate probe location method fields
+ */
+ lookup_type = lttng_userspace_probe_location_lookup_method_get_type(
+ location->lookup_method);
+ switch (lookup_type) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+ lookup_method =
+ lttng_userspace_probe_location_lookup_method_function_elf_copy(
+ location->lookup_method);
+ if (!lookup_method) {
+ goto error;
+ }
+ break;
+ default:
+ /* Invalid probe location lookup method. */
+ goto error;
+ }
+
+ /* Create the probe_location */
+ new_location = lttng_userspace_probe_location_function_create_no_check(
+ binary_path, function_name, lookup_method, false);
+ if (!new_location) {
+ goto destroy_lookup_method;
+ }
+
+ /* Set the duplicated fd to the new probe_location */
+ if (lttng_userspace_probe_location_function_set_binary_fd_handle(new_location,
+ function_location->binary_fd_handle) < 0) {
+ goto destroy_probe_location;
+ }
+
+ goto end;
+
+destroy_probe_location:
+ lttng_userspace_probe_location_destroy(new_location);
+destroy_lookup_method:
+ lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
+error:
+ new_location = NULL;
+end:
+ return new_location;
+}
+
+static struct lttng_userspace_probe_location *
+lttng_userspace_probe_location_tracepoint_copy(
+ const struct lttng_userspace_probe_location *location)
+{
+ enum lttng_userspace_probe_location_lookup_method_type lookup_type;
+ struct lttng_userspace_probe_location *new_location = NULL;
+ struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
+ const char *binary_path = NULL;
+ const char *probe_name = NULL;
+ const char *provider_name = NULL;
+ struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
+
+ assert(location);
+ assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
+ tracepoint_location = container_of(
+ location, typeof(*tracepoint_location), parent);
+
+ /* Get probe location fields */
+ binary_path = lttng_userspace_probe_location_tracepoint_get_binary_path(location);
+ if (!binary_path) {
+ ERR("Userspace probe binary path is NULL");
+ goto error;
+ }
+
+ probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(location);
+ if (!probe_name) {
+ ERR("Userspace probe probe name is NULL");
+ goto error;
+ }
+
+ provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(location);
+ if (!provider_name) {
+ ERR("Userspace probe provider name is NULL");
+ goto error;
+ }
+
+ /*
+ * Duplicate probe location method fields
+ */
+ lookup_type = lttng_userspace_probe_location_lookup_method_get_type(
+ location->lookup_method);
+ switch (lookup_type) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+ lookup_method =
+ lttng_userspace_probe_location_lookup_method_tracepoint_sdt_copy(
+ location->lookup_method);
+ if (!lookup_method) {
+ goto error;
+ }
+ break;
+ default:
+ /* Invalid probe location lookup method. */
+ goto error;
+ }
+
+ /* Create the probe_location */
+ new_location = lttng_userspace_probe_location_tracepoint_create_no_check(
+ binary_path, provider_name, probe_name, lookup_method, false);
+ if (!new_location) {
+ goto destroy_lookup_method;
+ }
+
+ /* Set the duplicated fd to the new probe_location */
+ if (lttng_userspace_probe_location_tracepoint_set_binary_fd_handle(new_location,
+ tracepoint_location->binary_fd_handle) < 0) {
+ goto destroy_probe_location;
+ }