+static
+int lttng_userspace_probe_location_tracepoint_flatten(
+ const struct lttng_userspace_probe_location *location,
+ struct lttng_dynamic_buffer *buffer)
+{
+ struct lttng_userspace_probe_location_lookup_method_sdt flat_lookup_method;
+ struct lttng_userspace_probe_location_tracepoint *probe_tracepoint;
+ struct lttng_userspace_probe_location_tracepoint flat_probe;
+ size_t probe_name_len, provider_name_len, binary_path_len;
+ size_t padding_needed = 0;
+ int storage_needed = 0;
+ char *flat_probe_start;
+ int ret = 0;
+
+ assert(location);
+
+ /* Only SDT tracepoints are supported at the moment */
+ if (location->lookup_method && location->lookup_method->type !=
+ LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ probe_tracepoint = container_of(location,
+ struct lttng_userspace_probe_location_tracepoint,
+ parent);
+ assert(probe_tracepoint->probe_name);
+ assert(probe_tracepoint->provider_name);
+ assert(probe_tracepoint->binary_path);
+
+ /* Compute the storage space needed to flatten the probe location */
+ storage_needed += sizeof(struct lttng_userspace_probe_location_tracepoint);
+
+ probe_name_len = strlen(probe_tracepoint->probe_name) + 1;
+ provider_name_len = strlen(probe_tracepoint->provider_name) + 1;
+ binary_path_len = strlen(probe_tracepoint->binary_path) + 1;
+
+ storage_needed += probe_name_len + provider_name_len + binary_path_len;
+
+ /*
+ * The lookup method is aligned to 64-bit within the buffer.
+ * This is needed even if there is no lookup method since
+ * the next structure in the buffer probably needs to be
+ * aligned too (depending on the arch).
+ */
+ padding_needed = ALIGN_TO(storage_needed, sizeof(uint64_t)) - storage_needed;
+ storage_needed += padding_needed;
+
+ if (location->lookup_method) {
+ /* NOTE: elf look-up method is assumed here. */
+ storage_needed +=
+ sizeof(struct lttng_userspace_probe_location_lookup_method_elf);
+ }
+
+ /*
+ * If the caller set buffer to NULL, return the size of the needed buffer.
+ */
+ if (!buffer) {
+ ret = storage_needed;
+ goto end;
+ }
+
+ if (lttng_dynamic_buffer_get_capacity_left(buffer) < storage_needed) {
+ ret = lttng_dynamic_buffer_set_capacity(buffer,
+ buffer->size + storage_needed);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ memset(&flat_probe, 0, sizeof(flat_probe));
+
+ flat_probe_start = buffer->data + buffer->size;
+ flat_probe.parent.type = location->type;
+
+ /*
+ * The lookup method, if present, is the last element in the flat
+ * representation of the probe.
+ */
+ if (location->lookup_method) {
+ flat_probe.parent.lookup_method =
+ (struct lttng_userspace_probe_location_lookup_method *)
+ (flat_probe_start + sizeof(flat_probe) +
+ probe_name_len + provider_name_len +
+ binary_path_len + padding_needed);
+ } else {
+ flat_probe.parent.lookup_method = NULL;
+ }
+
+ flat_probe.probe_name = flat_probe_start + sizeof(flat_probe);
+ flat_probe.provider_name = flat_probe.probe_name + probe_name_len;
+ flat_probe.binary_path = flat_probe.provider_name + provider_name_len;
+ flat_probe.binary_fd = -1;
+ ret = lttng_dynamic_buffer_append(buffer, &flat_probe, sizeof(flat_probe));
+ if (ret) {
+ goto end;
+ }
+
+ /* Append all the fields to the buffer */
+ ret = lttng_dynamic_buffer_append(buffer,
+ probe_tracepoint->probe_name, probe_name_len);
+ if (ret) {
+ goto end;
+ }
+ ret = lttng_dynamic_buffer_append(buffer,
+ probe_tracepoint->provider_name, provider_name_len);
+ if (ret) {
+ goto end;
+ }
+ ret = lttng_dynamic_buffer_append(buffer,
+ probe_tracepoint->binary_path, binary_path_len);
+ if (ret) {
+ goto end;
+ }
+
+ /* Insert padding before the lookup method. */
+ ret = lttng_dynamic_buffer_set_size(buffer, buffer->size + padding_needed);
+ if (ret) {
+ goto end;
+ }
+
+ if (!location->lookup_method) {
+ /* Not an error, the default method is used. */
+ ret = storage_needed;
+ goto end;
+ }
+
+ memset(&flat_lookup_method, 0, sizeof(flat_lookup_method));
+
+ flat_lookup_method.parent.type =
+ LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT;
+ ret = lttng_dynamic_buffer_append(buffer,
+ &flat_lookup_method, sizeof(flat_lookup_method));
+ if (ret) {
+ goto end;
+ }
+ ret = storage_needed;
+end:
+ return ret;
+}
+