From: Francis Deslauriers Date: Thu, 28 Jun 2018 14:06:23 +0000 (-0400) Subject: Add SDT userspace probe location X-Git-Tag: v2.11.0-rc1~83 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=f4d0bb2e92e94cb5eb304c8e92afcc804591539d;p=lttng-tools.git Add SDT userspace probe location SDT userspace probe location is of the tracepoint location type. Tracepoint locations describe an instrumentation location using a provider name and a probe name. Signed-off-by: Francis Deslauriers Signed-off-by: Jérémie Galarneau --- diff --git a/include/lttng/userspace-probe-internal.h b/include/lttng/userspace-probe-internal.h index 9c580323c..8708ec01c 100644 --- a/include/lttng/userspace-probe-internal.h +++ b/include/lttng/userspace-probe-internal.h @@ -44,6 +44,10 @@ struct lttng_userspace_probe_location_lookup_method_elf { struct lttng_userspace_probe_location_lookup_method parent; }; +struct lttng_userspace_probe_location_lookup_method_sdt { + struct lttng_userspace_probe_location_lookup_method parent; +}; + struct lttng_userspace_probe_location_comm { /* enum lttng_userspace_probe_location_type */ int8_t type; @@ -67,6 +71,20 @@ struct lttng_userspace_probe_location_function_comm { char payload[]; } LTTNG_PACKED; +struct lttng_userspace_probe_location_tracepoint_comm { + /* The three lengths include the trailing \0. */ + uint32_t probe_name_len; + uint32_t provider_name_len; + uint32_t binary_path_len; + /* + * Payload is composed of, in that order, + * - probe name (with trailing \0), + * - provider name (with trailing \0), + * - absolute binary path (with trailing \0) + */ + char payload[]; +} LTTNG_PACKED; + /* Common ancestor of all userspace probe locations. */ struct lttng_userspace_probe_location { enum lttng_userspace_probe_location_type type; @@ -86,6 +104,20 @@ struct lttng_userspace_probe_location_function { int binary_fd; }; +struct lttng_userspace_probe_location_tracepoint { + struct lttng_userspace_probe_location parent; + char *probe_name; + char *provider_name; + char *binary_path; + /* + * binary_fd is a file descriptor to the executable file. It's open + * early on to keep the backing inode valid over the course of the + * intrumentation and use. It prevents deletion and reuse races. + * Set to -1 if not open. + */ + int binary_fd; +}; + LTTNG_HIDDEN int lttng_userspace_probe_location_serialize( const struct lttng_userspace_probe_location *location, @@ -101,6 +133,10 @@ LTTNG_HIDDEN int lttng_userspace_probe_location_function_set_binary_fd( struct lttng_userspace_probe_location *location, int binary_fd); +LTTNG_HIDDEN +int lttng_userspace_probe_location_tracepoint_set_binary_fd( + struct lttng_userspace_probe_location *location, int binary_fd); + /* * Returns a version of the location that is serialized to a contiguous region * of memory. Pass NULL to buffer to only get the storage requirement of the diff --git a/include/lttng/userspace-probe.h b/include/lttng/userspace-probe.h index 4c92c36b2..c8c1ae43a 100644 --- a/include/lttng/userspace-probe.h +++ b/include/lttng/userspace-probe.h @@ -32,6 +32,7 @@ enum lttng_userspace_probe_location_lookup_method_type { LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_UNKNOWN = -1, LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT = 0, LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF = 1, + LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT = 2, }; /* @@ -54,6 +55,13 @@ extern void lttng_userspace_probe_location_lookup_method_destroy( extern struct lttng_userspace_probe_location_lookup_method * lttng_userspace_probe_location_lookup_method_function_elf_create(void); +/* + * Create a tracepoint SDT tracepoint lookup method struct. + * Return NULL on failure. + */ +extern struct lttng_userspace_probe_location_lookup_method * +lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create(void); + /* * Contains all the information needed to compute the instrumentation point in @@ -64,6 +72,7 @@ struct lttng_userspace_probe_location; enum lttng_userspace_probe_location_type { LTTNG_USERSPACE_PROBE_LOCATION_TYPE_UNKNOWN = -1, LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION = 0, + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT = 1, }; /* @@ -121,6 +130,46 @@ extern struct lttng_userspace_probe_location_lookup_method * lttng_userspace_probe_location_get_lookup_method( const struct lttng_userspace_probe_location *location); +/* + * Create a probe location of the tracepoint type. + * Receives the target binary file path, probename and probe provider to + * instrument. + * On failure, NULL is returned. + * + * The ownership of the lookup method is transferred to the created probe + * location. + */ +extern struct lttng_userspace_probe_location * +lttng_userspace_probe_location_tracepoint_create(const char *binary_path, + const char *probe_name, const char *provider_name, + struct lttng_userspace_probe_location_lookup_method *lookup_method); + +/* + * Get the target binary path of the probe location of the tracepoint type. + */ +extern const char *lttng_userspace_probe_location_tracepoint_get_binary_path( + const struct lttng_userspace_probe_location *location); + +/* + * Get the target probe name of the probe location of the tracepoint type. + */ +extern const char *lttng_userspace_probe_location_tracepoint_get_probe_name( + const struct lttng_userspace_probe_location *location); + +/* + * Get the target probe provider name of the probe location of the tracepoint + * type. + */ +extern const char *lttng_userspace_probe_location_tracepoint_get_provider_name( + const struct lttng_userspace_probe_location *location); + +/* + * Get the FD to the target binary file to the probe location of the tracepoint + * type. + */ +extern int lttng_userspace_probe_location_tracepoint_get_binary_fd( + const struct lttng_userspace_probe_location *location); + #ifdef __cplusplus } #endif diff --git a/src/common/userspace-probe.c b/src/common/userspace-probe.c index 78cf43b27..ea3c93bcd 100644 --- a/src/common/userspace-probe.c +++ b/src/common/userspace-probe.c @@ -47,6 +47,14 @@ void lttng_userspace_probe_location_lookup_method_destroy( free(elf_method); break; } + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + { + struct lttng_userspace_probe_location_lookup_method_sdt *sdt_method = + container_of(lookup_method, + struct lttng_userspace_probe_location_lookup_method_sdt, parent); + free(sdt_method); + break; + } default: break; } @@ -70,6 +78,24 @@ end: return ret; } +struct lttng_userspace_probe_location_lookup_method * +lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create(void) +{ + struct lttng_userspace_probe_location_lookup_method *ret = NULL; + struct lttng_userspace_probe_location_lookup_method_sdt *sdt_method; + + sdt_method = zmalloc(sizeof(*sdt_method)); + if (!sdt_method) { + PERROR("zmalloc"); + goto end; + } + + ret = &sdt_method->parent; + ret->type = LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT; +end: + return ret; +} + enum lttng_userspace_probe_location_type lttng_userspace_probe_location_get_type( const struct lttng_userspace_probe_location *location) { @@ -100,6 +126,31 @@ void lttng_userspace_probe_location_function_destroy( free(location); } +static +void lttng_userspace_probe_location_tracepoint_destroy( + struct lttng_userspace_probe_location *location) +{ + struct lttng_userspace_probe_location_tracepoint *location_tracepoint = NULL; + + assert(location); + + location_tracepoint = container_of(location, + struct lttng_userspace_probe_location_tracepoint, + parent); + + assert(location_tracepoint); + + free(location_tracepoint->probe_name); + free(location_tracepoint->provider_name); + free(location_tracepoint->binary_path); + if (location_tracepoint->binary_fd >= 0) { + if (close(location_tracepoint->binary_fd)) { + PERROR("close"); + } + } + free(location); +} + void lttng_userspace_probe_location_destroy( struct lttng_userspace_probe_location *location) { @@ -114,6 +165,9 @@ void lttng_userspace_probe_location_destroy( case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION: lttng_userspace_probe_location_function_destroy(location); break; + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + lttng_userspace_probe_location_tracepoint_destroy(location); + break; default: free(location); } @@ -179,6 +233,75 @@ end: return ret; } +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; + 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; + } + } else { + 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 = binary_fd; + + ret = &location->parent; + ret->lookup_method = lookup_method; + ret->type = LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT; + goto end; + +error: + free(probe_name_copy); + free(provider_name_copy); + if (binary_fd >= 0) { + if (close(binary_fd)) { + PERROR("Error closing binary fd in error path"); + } + } +end: + return ret; +} + struct lttng_userspace_probe_location * lttng_userspace_probe_location_function_create(const char *binary_path, const char *function_name, @@ -207,6 +330,33 @@ 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)"); + 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) @@ -234,6 +384,34 @@ 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) @@ -320,6 +498,103 @@ 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; + char *binary_path = NULL; + char *probe_name = NULL; + char *provider_name = NULL; + int fd; + + assert(location); + assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT); + + /* Duplicate probe location fields */ + binary_path = + lttng_strndup(lttng_userspace_probe_location_tracepoint_get_binary_path(location), + LTTNG_PATH_MAX); + if (!binary_path) { + PERROR("lttng_strndup"); + goto error; + } + + probe_name = + lttng_strndup(lttng_userspace_probe_location_tracepoint_get_probe_name(location), + LTTNG_SYMBOL_NAME_LEN); + if (!probe_name) { + PERROR("lttng_strndup"); + goto error; + } + + provider_name = + lttng_strndup(lttng_userspace_probe_location_tracepoint_get_provider_name(location), + LTTNG_SYMBOL_NAME_LEN); + if (!provider_name) { + PERROR("lttng_strndup"); + goto error; + } + + /* Duplicate the binary fd */ + fd = dup(lttng_userspace_probe_location_tracepoint_get_binary_fd(location)); + if (fd == -1) { + PERROR("dup"); + 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 close_fd; + } + break; + default: + /* Invalid probe location lookup method. */ + goto close_fd; + } + + /* Create the probe_location */ + new_location = lttng_userspace_probe_location_tracepoint_create_no_check( + binary_path, provider_name, probe_name, lookup_method, true); + 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(new_location, fd) < 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); +close_fd: + if (close(fd) < 0) { + PERROR("close"); + } +error: + free(provider_name); + free(probe_name); + free(binary_path); + new_location = NULL; +end: + return new_location; +} + const char *lttng_userspace_probe_location_function_get_binary_path( const struct lttng_userspace_probe_location *location) { @@ -340,6 +615,26 @@ end: return ret; } +const char *lttng_userspace_probe_location_tracepoint_get_binary_path( + const struct lttng_userspace_probe_location *location) +{ + const char *ret = NULL; + struct lttng_userspace_probe_location_tracepoint *tracepoint_location; + + if (!location || lttng_userspace_probe_location_get_type(location) != + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) { + ERR("Invalid argument(s)"); + goto end; + } + + tracepoint_location = container_of(location, + struct lttng_userspace_probe_location_tracepoint, + parent); + ret = tracepoint_location->binary_path; +end: + return ret; +} + const char *lttng_userspace_probe_location_function_get_function_name( const struct lttng_userspace_probe_location *location) { @@ -359,6 +654,44 @@ end: return ret; } +const char *lttng_userspace_probe_location_tracepoint_get_probe_name( + const struct lttng_userspace_probe_location *location) +{ + const char *ret = NULL; + struct lttng_userspace_probe_location_tracepoint *tracepoint_location; + + if (!location || lttng_userspace_probe_location_get_type(location) != + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) { + ERR("Invalid argument(s)"); + goto end; + } + + tracepoint_location = container_of(location, + struct lttng_userspace_probe_location_tracepoint, parent); + ret = tracepoint_location->probe_name; +end: + return ret; +} + +const char *lttng_userspace_probe_location_tracepoint_get_provider_name( + const struct lttng_userspace_probe_location *location) +{ + const char *ret = NULL; + struct lttng_userspace_probe_location_tracepoint *tracepoint_location; + + if (!location || lttng_userspace_probe_location_get_type(location) != + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) { + ERR("Invalid argument(s)"); + goto end; + } + + tracepoint_location = container_of(location, + struct lttng_userspace_probe_location_tracepoint, parent); + ret = tracepoint_location->provider_name; +end: + return ret; +} + int lttng_userspace_probe_location_function_get_binary_fd( const struct lttng_userspace_probe_location *location) { @@ -378,6 +711,25 @@ end: return ret; } +int lttng_userspace_probe_location_tracepoint_get_binary_fd( + const struct lttng_userspace_probe_location *location) +{ + int ret = -1; + struct lttng_userspace_probe_location_tracepoint *tracepoint_location; + + if (!location || lttng_userspace_probe_location_get_type(location) != + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) { + ERR("Invalid argument(s)"); + goto end; + } + + tracepoint_location = container_of(location, + struct lttng_userspace_probe_location_tracepoint, parent); + ret = tracepoint_location->binary_fd; +end: + return ret; +} + static struct lttng_userspace_probe_location_lookup_method * lttng_userspace_probe_location_function_get_lookup_method( const struct lttng_userspace_probe_location *location) @@ -395,6 +747,23 @@ end: return ret; } +static struct lttng_userspace_probe_location_lookup_method * +lttng_userspace_probe_location_tracepoint_get_lookup_method( + const struct lttng_userspace_probe_location *location) +{ + struct lttng_userspace_probe_location_lookup_method *ret = NULL; + + if (!location || lttng_userspace_probe_location_get_type(location) != + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT) { + ERR("Invalid argument(s)"); + goto end; + } + + ret = location->lookup_method; +end: + return ret; +} + struct lttng_userspace_probe_location_lookup_method * lttng_userspace_probe_location_get_lookup_method( const struct lttng_userspace_probe_location *location) @@ -407,6 +776,10 @@ lttng_userspace_probe_location_get_lookup_method( ret = lttng_userspace_probe_location_function_get_lookup_method( location); break; + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + ret = lttng_userspace_probe_location_tracepoint_get_lookup_method( + location); + break; default: ERR("Unknowned lookup method."); break; @@ -432,83 +805,177 @@ int lttng_userspace_probe_location_lookup_method_serialize( goto end; } } - ret = sizeof(lookup_method_comm); + ret = sizeof(lookup_method_comm); +end: + return ret; +} + +static +int lttng_userspace_probe_location_function_serialize( + const struct lttng_userspace_probe_location *location, + struct lttng_dynamic_buffer *buffer, + int *binary_fd) +{ + int ret; + size_t function_name_len, binary_path_len; + 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_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION); + + location_function = container_of(location, + struct lttng_userspace_probe_location_function, + parent); + if (!location_function->function_name || !location_function->binary_path) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (binary_fd && location_function->binary_fd < 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (binary_fd) { + *binary_fd = location_function->binary_fd; + } + + function_name_len = strlen(location_function->function_name); + if (function_name_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + binary_path_len = strlen(location_function->binary_path); + if (binary_path_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + location_function_comm.function_name_len = function_name_len + 1; + location_function_comm.binary_path_len = binary_path_len + 1; + + if (buffer) { + ret = lttng_dynamic_buffer_append(buffer, + &location_function_comm, + sizeof(location_function_comm)); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + ret = lttng_dynamic_buffer_append(buffer, + location_function->function_name, + location_function_comm.function_name_len); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + ret = lttng_dynamic_buffer_append(buffer, + location_function->binary_path, + location_function_comm.binary_path_len); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + } + ret = sizeof(location_function_comm) + + location_function_comm.function_name_len + + location_function_comm.binary_path_len; end: return ret; } static -int lttng_userspace_probe_location_function_serialize( +int lttng_userspace_probe_location_tracepoint_serialize( const struct lttng_userspace_probe_location *location, struct lttng_dynamic_buffer *buffer, int *binary_fd) { int ret; - size_t function_name_len, binary_path_len; - struct lttng_userspace_probe_location_function *location_function; - struct lttng_userspace_probe_location_function_comm location_function_comm; + size_t probe_name_len, provider_name_len, binary_path_len; + 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_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION); + LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT); - location_function = container_of(location, - struct lttng_userspace_probe_location_function, + location_tracepoint = container_of(location, + struct lttng_userspace_probe_location_tracepoint, parent); - if (!location_function->function_name || !location_function->binary_path) { + if (!location_tracepoint->probe_name || + !location_tracepoint->provider_name || + !location_tracepoint->binary_path) { ret = -LTTNG_ERR_INVALID; goto end; } - if (binary_fd && location_function->binary_fd < 0) { + if (binary_fd && location_tracepoint->binary_fd < 0) { ret = -LTTNG_ERR_INVALID; goto end; } if (binary_fd) { - *binary_fd = location_function->binary_fd; + *binary_fd = location_tracepoint->binary_fd; } - function_name_len = strlen(location_function->function_name); - if (function_name_len == 0) { + probe_name_len = strlen(location_tracepoint->probe_name); + if (probe_name_len == 0) { ret = -LTTNG_ERR_INVALID; goto end; } - binary_path_len = strlen(location_function->binary_path); + + provider_name_len = strlen(location_tracepoint->provider_name); + if (provider_name_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + binary_path_len = strlen(location_tracepoint->binary_path); if (binary_path_len == 0) { ret = -LTTNG_ERR_INVALID; goto end; } - location_function_comm.function_name_len = function_name_len + 1; - location_function_comm.binary_path_len = binary_path_len + 1; + location_tracepoint_comm.probe_name_len = probe_name_len + 1; + location_tracepoint_comm.provider_name_len = provider_name_len + 1; + location_tracepoint_comm.binary_path_len = binary_path_len + 1; if (buffer) { ret = lttng_dynamic_buffer_append(buffer, - &location_function_comm, - sizeof(location_function_comm)); + &location_tracepoint_comm, + sizeof(location_tracepoint_comm)); if (ret) { ret = -LTTNG_ERR_INVALID; goto end; } ret = lttng_dynamic_buffer_append(buffer, - location_function->function_name, - location_function_comm.function_name_len); + location_tracepoint->probe_name, + location_tracepoint_comm.probe_name_len); if (ret) { ret = -LTTNG_ERR_INVALID; goto end; } ret = lttng_dynamic_buffer_append(buffer, - location_function->binary_path, - location_function_comm.binary_path_len); + location_tracepoint->provider_name, + location_tracepoint_comm.provider_name_len); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + ret = lttng_dynamic_buffer_append(buffer, + location_tracepoint->binary_path, + location_tracepoint_comm.binary_path_len); if (ret) { ret = -LTTNG_ERR_INVALID; goto end; } } - ret = sizeof(location_function_comm) + - location_function_comm.function_name_len + - location_function_comm.binary_path_len; + ret = sizeof(location_tracepoint_comm) + + location_tracepoint_comm.probe_name_len + + location_tracepoint_comm.provider_name_len + + location_tracepoint_comm.binary_path_len; end: return ret; } @@ -545,6 +1012,10 @@ int lttng_userspace_probe_location_serialize( ret = lttng_userspace_probe_location_function_serialize( location, buffer, binary_fd); break; + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + ret = lttng_userspace_probe_location_tracepoint_serialize( + location, buffer, binary_fd); + break; default: ERR("Unsupported probe location type"); ret = -LTTNG_ERR_INVALID; @@ -630,6 +1101,86 @@ end: return ret; } +static +int lttng_userspace_probe_location_tracepoint_create_from_buffer( + const struct lttng_buffer_view *buffer, + struct lttng_userspace_probe_location **location) +{ + struct lttng_userspace_probe_location_tracepoint_comm *location_tracepoint_comm; + const char *probe_name_src, *provider_name_src, *binary_path_src; + char *probe_name = NULL, *provider_name = NULL, *binary_path = NULL; + int ret = 0; + + assert(buffer); + assert(buffer->data); + assert(location); + + location_tracepoint_comm = + (struct lttng_userspace_probe_location_tracepoint_comm *) buffer->data; + + const size_t expected_size = sizeof(*location_tracepoint_comm) + + location_tracepoint_comm->probe_name_len + + location_tracepoint_comm->provider_name_len + + location_tracepoint_comm->binary_path_len; + + if (buffer->size < expected_size) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + probe_name_src = buffer->data + sizeof(*location_tracepoint_comm); + provider_name_src = probe_name_src + + location_tracepoint_comm->probe_name_len; + binary_path_src = provider_name_src + + location_tracepoint_comm->provider_name_len; + + if (probe_name_src[location_tracepoint_comm->probe_name_len - 1] != '\0') { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (provider_name_src[location_tracepoint_comm->provider_name_len - 1] != '\0') { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (binary_path_src[location_tracepoint_comm->binary_path_len - 1] != '\0') { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + probe_name = lttng_strndup(probe_name_src, LTTNG_SYMBOL_NAME_LEN); + if (!probe_name) { + PERROR("lttng_strndup"); + goto end; + } + provider_name = lttng_strndup(provider_name_src, LTTNG_SYMBOL_NAME_LEN); + if (!provider_name) { + PERROR("lttng_strndup"); + goto end; + } + + binary_path = lttng_strndup(binary_path_src, LTTNG_SYMBOL_NAME_LEN); + if (!binary_path) { + PERROR("lttng_strndup"); + goto end; + } + + *location = lttng_userspace_probe_location_tracepoint_create_no_check( + binary_path, provider_name, probe_name, NULL, false); + if (!(*location)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = (int) expected_size; +end: + free(probe_name); + free(provider_name); + free(binary_path); + return ret; +} + static int lttng_userspace_probe_location_lookup_method_create_from_buffer( struct lttng_buffer_view *buffer, @@ -664,6 +1215,14 @@ int lttng_userspace_probe_location_lookup_method_create_from_buffer( goto end; } break; + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + *lookup_method = + lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create(); + if (!(*lookup_method)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + break; default: ret = -LTTNG_ERR_INVALID; goto end; @@ -716,6 +1275,18 @@ int lttng_userspace_probe_location_create_from_buffer( } break; } + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + { + struct lttng_buffer_view view = lttng_buffer_view_from_view( + buffer, consumed, buffer->size - consumed); + + ret = lttng_userspace_probe_location_tracepoint_create_from_buffer( + &view, location); + if (ret < 0) { + goto end; + } + break; + } default: ret = -LTTNG_ERR_INVALID; goto end; @@ -770,6 +1341,32 @@ end: return ret; } +LTTNG_HIDDEN +int lttng_userspace_probe_location_tracepoint_set_binary_fd( + struct lttng_userspace_probe_location *location, int binary_fd) +{ + int ret = 0; + struct lttng_userspace_probe_location_tracepoint *tracepoint_location; + + assert(location); + assert(location->type == LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT); + + tracepoint_location = container_of(location, + struct lttng_userspace_probe_location_tracepoint, parent); + if (tracepoint_location->binary_fd >= 0) { + ret = close(tracepoint_location->binary_fd); + if (ret) { + PERROR("close"); + ret = -LTTNG_ERR_INVALID; + goto end; + } + } + + tracepoint_location->binary_fd = binary_fd; +end: + return ret; +} + static int lttng_userspace_probe_location_function_flatten( const struct lttng_userspace_probe_location *location, @@ -894,6 +1491,146 @@ end: return ret; } +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; +} + LTTNG_HIDDEN int lttng_userspace_probe_location_flatten( const struct lttng_userspace_probe_location *location, @@ -910,6 +1647,9 @@ int lttng_userspace_probe_location_flatten( case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION: ret = lttng_userspace_probe_location_function_flatten(location, buffer); break; + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + ret = lttng_userspace_probe_location_tracepoint_flatten(location, buffer); + break; default: ret = -LTTNG_ERR_INVALID; goto end; @@ -939,6 +1679,13 @@ struct lttng_userspace_probe_location *lttng_userspace_probe_location_copy( goto err; } break; + case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT: + new_location = + lttng_userspace_probe_location_tracepoint_copy(location); + if (!new_location) { + goto err; + } + break; default: new_location = NULL; goto err;