*/
#include "lttng/lttng-error.h"
-#include <assert.h>
#include <common/compat/string.h>
+#include <common/align.h>
#include <common/error.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
#include <common/macros.h>
-#include <common/payload.h>
+#include <common/mi-lttng.h>
#include <common/payload-view.h>
+#include <common/payload.h>
#include <fcntl.h>
#include <lttng/constant.h>
#include <lttng/userspace-probe-internal.h>
struct lttng_userspace_probe_location *location,
struct fd_handle *binary_fd_handle);
+static
+enum lttng_error_code lttng_userspace_probe_location_lookup_method_mi_serialize(
+ const struct lttng_userspace_probe_location_lookup_method
+ *method,
+ struct mi_writer *writer);
+
+static
+enum lttng_error_code lttng_userspace_probe_location_tracepoint_mi_serialize(
+ const struct lttng_userspace_probe_location *location,
+ struct mi_writer *writer);
+
+static
+enum lttng_error_code lttng_userspace_probe_location_function_mi_serialize(
+ const struct lttng_userspace_probe_location *location,
+ struct mi_writer *writer);
+
enum lttng_userspace_probe_location_lookup_method_type
lttng_userspace_probe_location_lookup_method_get_type(
const struct lttng_userspace_probe_location_lookup_method *lookup_method)
{
struct lttng_userspace_probe_location_function *location_function = NULL;
- assert(location);
+ LTTNG_ASSERT(location);
location_function = container_of(location,
struct lttng_userspace_probe_location_function, parent);
- assert(location_function);
+ LTTNG_ASSERT(location_function);
free(location_function->function_name);
free(location_function->binary_path);
{
struct lttng_userspace_probe_location_tracepoint *location_tracepoint = NULL;
- assert(location);
+ LTTNG_ASSERT(location);
location_tracepoint = container_of(location,
struct lttng_userspace_probe_location_tracepoint,
parent);
- assert(location_tracepoint);
+ LTTNG_ASSERT(location_tracepoint);
free(location_tracepoint->probe_name);
free(location_tracepoint->provider_name);
return is_equal;
}
+static unsigned long lttng_userspace_probe_location_function_hash(
+ const struct lttng_userspace_probe_location *location)
+{
+ unsigned long hash = hash_key_ulong(
+ (void *) LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION,
+ lttng_ht_seed);
+ struct lttng_userspace_probe_location_function *function_location =
+ container_of(location, typeof(*function_location),
+ parent);
+
+ hash ^= hash_key_str(function_location->function_name, lttng_ht_seed);
+ hash ^= hash_key_str(function_location->binary_path, lttng_ht_seed);
+ /*
+ * No need to hash on the fd. Worst comes to worse,
+ * the equal function will discriminate.
+ */
+ return hash;
+}
+
static bool lttng_userspace_probe_location_function_is_equal(
const struct lttng_userspace_probe_location *_a,
const struct lttng_userspace_probe_location *_b)
goto end;
}
- assert(a->function_name);
- assert(b->function_name);
+ LTTNG_ASSERT(a->function_name);
+ LTTNG_ASSERT(b->function_name);
if (strcmp(a->function_name, b->function_name)) {
goto end;
}
- assert(a->binary_path);
- assert(b->binary_path);
+ LTTNG_ASSERT(a->binary_path);
+ LTTNG_ASSERT(b->binary_path);
if (strcmp(a->binary_path, b->binary_path)) {
goto end;
}
ret->lookup_method = lookup_method;
ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION;
ret->equal = lttng_userspace_probe_location_function_is_equal;
+ ret->hash = lttng_userspace_probe_location_function_hash;
goto end;
error:
return ret;
}
+static unsigned long lttng_userspace_probe_location_tracepoint_hash(
+ const struct lttng_userspace_probe_location *location)
+{
+ unsigned long hash = hash_key_ulong(
+ (void *) LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT,
+ lttng_ht_seed);
+ struct lttng_userspace_probe_location_tracepoint *tp_location =
+ container_of(location, typeof(*tp_location), parent);
+
+ hash ^= hash_key_str(tp_location->probe_name, lttng_ht_seed);
+ hash ^= hash_key_str(tp_location->provider_name, lttng_ht_seed);
+ hash ^= hash_key_str(tp_location->binary_path, lttng_ht_seed);
+ /*
+ * No need to hash on the fd. Worst comes to worse,
+ * the equal function will discriminate.
+ */
+ return hash;
+}
+
static bool lttng_userspace_probe_location_tracepoint_is_equal(
const struct lttng_userspace_probe_location *_a,
const struct lttng_userspace_probe_location *_b)
b = container_of(_b, struct lttng_userspace_probe_location_tracepoint,
parent);
- assert(a->probe_name);
- assert(b->probe_name);
+ LTTNG_ASSERT(a->probe_name);
+ LTTNG_ASSERT(b->probe_name);
if (strcmp(a->probe_name, b->probe_name)) {
goto end;
}
- assert(a->provider_name);
- assert(b->provider_name);
+ LTTNG_ASSERT(a->provider_name);
+ LTTNG_ASSERT(b->provider_name);
if (strcmp(a->provider_name, b->provider_name)) {
goto end;
}
- assert(a->binary_path);
- assert(b->binary_path);
+ LTTNG_ASSERT(a->binary_path);
+ LTTNG_ASSERT(b->binary_path);
if (strcmp(a->binary_path, b->binary_path)) {
goto end;
}
ret->lookup_method = lookup_method;
ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT;
ret->equal = lttng_userspace_probe_location_tracepoint_is_equal;
+ ret->hash = lttng_userspace_probe_location_tracepoint_hash;
goto end;
error:
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_ASSERT(lookup_method);
+ LTTNG_ASSERT(lookup_method->type ==
LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF);
elf_method = zmalloc(sizeof(*elf_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_ASSERT(lookup_method);
+ LTTNG_ASSERT(lookup_method->type ==
LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT);
sdt_method = zmalloc(sizeof(*sdt_method));
const char *function_name = NULL;
struct lttng_userspace_probe_location_function *function_location;
- assert(location);
- assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
function_location = container_of(
location, typeof(*function_location), parent);
const char *provider_name = NULL;
struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
- assert(location);
- assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
tracepoint_location = container_of(
location, typeof(*tracepoint_location), parent);
{
struct lttng_userspace_probe_location_lookup_method *ret = NULL;
- assert(location);
+ LTTNG_ASSERT(location);
switch (location->type) {
case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
ret = lttng_userspace_probe_location_function_get_lookup_method(
struct lttng_userspace_probe_location_function *location_function;
struct lttng_userspace_probe_location_function_comm location_function_comm;
- assert(location);
- assert(lttng_userspace_probe_location_get_type(location) ==
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(lttng_userspace_probe_location_get_type(location) ==
LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
location_function = container_of(location,
struct lttng_userspace_probe_location_tracepoint *location_tracepoint;
struct lttng_userspace_probe_location_tracepoint_comm location_tracepoint_comm;
- assert(location);
- assert(lttng_userspace_probe_location_get_type(location) ==
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(lttng_userspace_probe_location_get_type(location) ==
LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
location_tracepoint = container_of(location,
return ret;
}
-LTTNG_HIDDEN
int lttng_userspace_probe_location_serialize(
const struct lttng_userspace_probe_location *location,
struct lttng_payload *payload)
size_t expected_size;
struct fd_handle *binary_fd_handle = lttng_payload_view_pop_fd_handle(view);
- assert(location);
+ LTTNG_ASSERT(location);
if (view->buffer.size < sizeof(*location_function_comm)) {
ret = -LTTNG_ERR_INVALID;
size_t expected_size;
struct fd_handle *binary_fd_handle = lttng_payload_view_pop_fd_handle(view);
- assert(location);
+ LTTNG_ASSERT(location);
if (!binary_fd_handle) {
ret = -LTTNG_ERR_INVALID;
probe_name = lttng_strndup(probe_name_src, LTTNG_SYMBOL_NAME_LEN);
if (!probe_name) {
- PERROR("lttng_strndup");
+ PERROR("Failed to allocate probe name");
+ ret = -LTTNG_ERR_INVALID;
goto end;
}
provider_name = lttng_strndup(provider_name_src, LTTNG_SYMBOL_NAME_LEN);
if (!provider_name) {
- PERROR("lttng_strndup");
+ PERROR("Failed to allocate provider name");
+ ret = -LTTNG_ERR_INVALID;
goto end;
}
- binary_path = lttng_strndup(binary_path_src, LTTNG_SYMBOL_NAME_LEN);
+ binary_path = lttng_strndup(binary_path_src, LTTNG_PATH_MAX);
if (!binary_path) {
- PERROR("lttng_strndup");
+ PERROR("Failed to allocate binary path");
+ ret = -LTTNG_ERR_INVALID;
goto end;
}
struct lttng_userspace_probe_location_lookup_method_comm *lookup_comm;
enum lttng_userspace_probe_location_lookup_method_type type;
- assert(view);
- assert(lookup_method);
+ LTTNG_ASSERT(view);
+ LTTNG_ASSERT(lookup_method);
if (view->buffer.size < sizeof(*lookup_comm)) {
ret = -LTTNG_ERR_INVALID;
return ret;
}
-LTTNG_HIDDEN
int lttng_userspace_probe_location_create_from_payload(
struct lttng_payload_view *view,
struct lttng_userspace_probe_location **location)
lttng_payload_view_from_view(
view, 0, sizeof(*probe_location_comm));
- assert(view);
- assert(location);
+ LTTNG_ASSERT(view);
+ LTTNG_ASSERT(location);
lookup_method = NULL;
goto end;
}
- assert(lookup_method);
+ LTTNG_ASSERT(lookup_method);
(*location)->lookup_method = lookup_method;
lookup_method = NULL;
ret += consumed;
int ret = 0;
struct lttng_userspace_probe_location_function *function_location;
- assert(location);
- assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION);
function_location = container_of(location,
struct lttng_userspace_probe_location_function, parent);
int ret = 0;
struct lttng_userspace_probe_location_tracepoint *tracepoint_location;
- assert(location);
- assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT);
tracepoint_location = container_of(location,
struct lttng_userspace_probe_location_tracepoint, parent);
int storage_needed = 0;
int ret;
- assert(location);
+ LTTNG_ASSERT(location);
if (location->lookup_method && location->lookup_method->type !=
LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF) {
probe_function = container_of(location,
struct lttng_userspace_probe_location_function,
parent);
- assert(probe_function->function_name);
- assert(probe_function->binary_path);
+ LTTNG_ASSERT(probe_function->function_name);
+ LTTNG_ASSERT(probe_function->binary_path);
storage_needed +=
sizeof(struct lttng_userspace_probe_location_function);
* 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;
+ padding_needed = lttng_align_ceil(storage_needed, sizeof(uint64_t)) - storage_needed;
storage_needed += padding_needed;
if (location->lookup_method) {
char *flat_probe_start;
int ret = 0;
- assert(location);
+ LTTNG_ASSERT(location);
/* Only SDT tracepoints are supported at the moment */
if (location->lookup_method && location->lookup_method->type !=
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);
+ LTTNG_ASSERT(probe_tracepoint->probe_name);
+ LTTNG_ASSERT(probe_tracepoint->provider_name);
+ LTTNG_ASSERT(probe_tracepoint->binary_path);
/* Compute the storage space needed to flatten the probe location */
storage_needed += sizeof(struct lttng_userspace_probe_location_tracepoint);
* 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;
+ padding_needed = lttng_align_ceil(storage_needed, sizeof(uint64_t)) - storage_needed;
storage_needed += padding_needed;
if (location->lookup_method) {
return ret;
}
-LTTNG_HIDDEN
int lttng_userspace_probe_location_flatten(
const struct lttng_userspace_probe_location *location,
struct lttng_dynamic_buffer *buffer)
return ret;
}
-LTTNG_HIDDEN
struct lttng_userspace_probe_location *lttng_userspace_probe_location_copy(
const struct lttng_userspace_probe_location *location)
{
return new_location;
}
-LTTNG_HIDDEN
bool lttng_userspace_probe_location_lookup_method_is_equal(
const struct lttng_userspace_probe_location_lookup_method *a,
const struct lttng_userspace_probe_location_lookup_method *b)
return is_equal;
}
-LTTNG_HIDDEN
bool lttng_userspace_probe_location_is_equal(
const struct lttng_userspace_probe_location *a,
const struct lttng_userspace_probe_location *b)
end:
return is_equal;
}
+
+unsigned long lttng_userspace_probe_location_hash(
+ const struct lttng_userspace_probe_location *location)
+{
+ return location->hash(location);
+}
+
+enum lttng_error_code lttng_userspace_probe_location_mi_serialize(
+ const struct lttng_userspace_probe_location *location,
+ struct mi_writer *writer)
+{
+ typedef enum lttng_error_code (*mi_fp)(
+ const struct lttng_userspace_probe_location *,
+ struct mi_writer *);
+
+ int ret;
+ enum lttng_error_code ret_code;
+ mi_fp mi_function = NULL;
+
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(writer);
+
+ switch (lttng_userspace_probe_location_get_type(location)) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
+ mi_function = lttng_userspace_probe_location_function_mi_serialize;
+ break;
+ case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
+ mi_function = lttng_userspace_probe_location_tracepoint_mi_serialize;
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ /* Open userspace probe location element. */
+ ret = mi_lttng_writer_open_element(
+ writer, mi_lttng_element_userspace_probe_location);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Underlying user space probe location. */
+ ret_code = mi_function(location, writer);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+
+ /* Close userspace probe location element. */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ goto mi_error;
+ }
+
+ ret_code = LTTNG_OK;
+ goto end;
+
+mi_error:
+ ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+ return ret_code;
+}
+
+enum lttng_error_code lttng_userspace_probe_location_lookup_method_mi_serialize(
+ const struct lttng_userspace_probe_location_lookup_method
+ *method,
+ struct mi_writer *writer)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ const char *type_element_str;
+
+ LTTNG_ASSERT(method);
+ LTTNG_ASSERT(writer);
+
+ switch (lttng_userspace_probe_location_lookup_method_get_type(method)) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
+ type_element_str =
+ mi_lttng_element_userspace_probe_location_lookup_method_function_default;
+ break;
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+ type_element_str =
+ mi_lttng_element_userspace_probe_location_lookup_method_function_elf;
+ break;
+ case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+ type_element_str =
+ mi_lttng_element_userspace_probe_location_lookup_method_tracepoint_sdt;
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ /* Open userspace probe location lookup method element. */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_userspace_probe_location_lookup_method);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* User space probe location lookup method empty element. */
+ ret = mi_lttng_writer_open_element(writer, type_element_str);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Close userspace probe location lookup method element. */
+ ret = mi_lttng_close_multi_element(writer, 2);
+ if (ret) {
+ goto mi_error;
+ }
+
+ ret_code = LTTNG_OK;
+ goto end;
+
+mi_error:
+ ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+ return ret_code;
+}
+
+static enum lttng_error_code lttng_userspace_probe_location_tracepoint_mi_serialize(
+ const struct lttng_userspace_probe_location *location,
+ struct mi_writer *writer)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ const char *probe_name = NULL;
+ const char *provider_name = NULL;
+ const char *binary_path = NULL;
+ const struct lttng_userspace_probe_location_lookup_method
+ *lookup_method = NULL;
+
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(writer);
+
+ probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(
+ location);
+ provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(
+ location);
+ binary_path = lttng_userspace_probe_location_tracepoint_get_binary_path(
+ location);
+ lookup_method = lttng_userspace_probe_location_tracepoint_get_lookup_method(
+ location);
+
+ /* Open userspace probe location tracepoint element. */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_userspace_probe_location_tracepoint);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Probe name. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_tracepoint_probe_name,
+ probe_name);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Provider name. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_tracepoint_provider_name,
+ provider_name);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Binary path. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_binary_path,
+ binary_path);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* The lookup method. */
+ ret_code = lttng_userspace_probe_location_lookup_method_mi_serialize(
+ lookup_method, writer);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+
+ /* Close userspace probe location tracepoint. */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ goto mi_error;
+ }
+
+ ret_code = LTTNG_OK;
+ goto end;
+
+mi_error:
+ ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+ return ret_code;
+}
+
+static enum lttng_error_code lttng_userspace_probe_location_function_mi_serialize(
+ const struct lttng_userspace_probe_location *location,
+ struct mi_writer *writer)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ const char *function_name = NULL;
+ const char *binary_path = NULL;
+ const char *instrumentation_type_str = NULL;
+ enum lttng_userspace_probe_location_function_instrumentation_type
+ instrumentation_type;
+ const struct lttng_userspace_probe_location_lookup_method
+ *lookup_method = NULL;
+
+ LTTNG_ASSERT(location);
+ LTTNG_ASSERT(writer);
+
+ function_name = lttng_userspace_probe_location_function_get_function_name(
+ location);
+ binary_path = lttng_userspace_probe_location_function_get_binary_path(
+ location);
+ instrumentation_type =
+ lttng_userspace_probe_location_function_get_instrumentation_type(
+ location);
+ lookup_method = lttng_userspace_probe_location_function_get_lookup_method(
+ location);
+
+ switch (instrumentation_type) {
+ case LTTNG_USERSPACE_PROBE_LOCATION_FUNCTION_INSTRUMENTATION_TYPE_ENTRY:
+ instrumentation_type_str =
+ mi_lttng_userspace_probe_location_function_instrumentation_type_entry;
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ /* Open userspace probe location function element. */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_userspace_probe_location_function);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Function name. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_function_name,
+ function_name);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Binary path. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_binary_path,
+ binary_path);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* Instrumentation type. */
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_userspace_probe_location_function_instrumentation_type,
+ instrumentation_type_str);
+ if (ret) {
+ goto mi_error;
+ }
+
+ /* The lookup method. */
+ ret_code = lttng_userspace_probe_location_lookup_method_mi_serialize(
+ lookup_method, writer);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+
+ /* Close userspace probe location function element. */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ goto mi_error;
+ }
+
+ ret_code = LTTNG_OK;
+ goto end;
+
+mi_error:
+ ret_code = LTTNG_ERR_MI_IO_FAIL;
+end:
+ return ret_code;
+}