*/
#define _LGPL_SOURCE
-#include <stdbool.h>
+#include "kernel.hpp"
+#include "lttng-sessiond.hpp"
+#include "lttng-syscall.hpp"
+#include "utils.hpp"
#include <common/common.hpp>
#include <common/kernel-ctl/kernel-ctl.hpp>
+#include <common/urcu.hpp>
-#include "lttng-sessiond.hpp"
-#include "kernel.hpp"
-#include "lttng-syscall.hpp"
-#include "utils.hpp"
+#include <stdbool.h>
/* Global syscall table. */
-struct syscall *syscall_table;
-
-/* Number of entry in the syscall table. */
-static size_t syscall_table_nb_entry;
+std::vector<struct syscall> syscall_table;
/*
* Populate the system call table using the kernel tracer.
int syscall_init_table(int tracer_fd)
{
int ret, fd, err;
- size_t nbmem;
FILE *fp;
/* Syscall data from the kernel. */
size_t index = 0;
- bool at_least_one_syscall = false;
uint32_t bitness;
char name[SYSCALL_NAME_LEN];
#if (SYSCALL_NAME_LEN == 255)
-#define SYSCALL_NAME_LEN_SCANF_IS_A_BROKEN_API "254"
+#define SYSCALL_NAME_LEN_SCANF_IS_A_BROKEN_API "254"
#endif
DBG3("Syscall init system call table");
goto error_fp;
}
- nbmem = SYSCALL_TABLE_INIT_SIZE;
- syscall_table = (struct syscall *) zmalloc(sizeof(struct syscall) * nbmem);
- if (!syscall_table) {
- ret = -errno;
- PERROR("syscall list zmalloc");
- goto error;
- }
-
while (fscanf(fp,
- "syscall { index = %zu; \
+ "syscall { index = %zu; \
name = %" SYSCALL_NAME_LEN_SCANF_IS_A_BROKEN_API "[^;]; \
bitness = %u; };\n",
- &index, name, &bitness) == 3) {
- at_least_one_syscall = true;
- if (index >= nbmem) {
- struct syscall *new_list;
- size_t new_nbmem;
-
- /* Double memory size. */
- new_nbmem = std::max(index + 1, nbmem << 1);
- if (new_nbmem > (SIZE_MAX / sizeof(*new_list))) {
- /* Overflow, stop everything, something went really wrong. */
- ERR("Syscall listing memory size overflow. Stopping");
- free(syscall_table);
- syscall_table = NULL;
- ret = -EINVAL;
- goto error;
- }
-
- DBG("Reallocating syscall table from %zu to %zu entries", nbmem,
- new_nbmem);
- new_list = (struct syscall *) realloc(syscall_table, new_nbmem * sizeof(*new_list));
- if (!new_list) {
- ret = -errno;
- PERROR("syscall list realloc");
- goto error;
- }
-
- /* Zero out the new memory. */
- memset(new_list + nbmem, 0,
- (new_nbmem - nbmem) * sizeof(*new_list));
- nbmem = new_nbmem;
- syscall_table = new_list;
- }
- syscall_table[index].index = index;
- syscall_table[index].bitness = bitness;
- if (lttng_strncpy(syscall_table[index].name, name,
- sizeof(syscall_table[index].name))) {
- ret = -EINVAL;
- free(syscall_table);
- syscall_table = NULL;
+ &index,
+ name,
+ &bitness) == 3) {
+ try {
+ syscall_table.emplace_back(index, bitness, name);
+ } catch (const std::bad_alloc&) {
+ ERR_FMT("Failed to add syscall to syscall table: table_current_element_count={}, syscall_name=`{}`",
+ syscall_table.size(),
+ name);
+ ret = ENOMEM;
+ goto error;
+ } catch (const lttng::invalid_argument_error& ex) {
+ ERR_FMT("Failed to add syscall to syscall table: table_current_element_count={}, reason=`{}`",
+ syscall_table.size(),
+ name,
+ ex.what());
+ ret = EINVAL;
goto error;
}
- /*
- DBG("Syscall name '%s' at index %" PRIu32 " of bitness %u",
- syscall_table[index].name,
- syscall_table[index].index,
- syscall_table[index].bitness);
- */
- }
-
- /* Index starts at 0. */
- if (at_least_one_syscall) {
- syscall_table_nb_entry = index + 1;
}
ret = 0;
* syscall hashtable used to track duplicate between 32 and 64 bit arch.
*
* This empty the hash table and destroys it after. After this, the pointer is
- * unsuable. RCU read side lock MUST be acquired before calling this.
+ * unsuable. RCU read side lock MUST NOT be acquired before calling this.
*/
static void destroy_syscall_ht(struct lttng_ht *ht)
{
- struct lttng_ht_iter iter;
- struct syscall *ksyscall;
-
- ASSERT_RCU_READ_LOCKED();
-
DBG3("Destroying syscall hash table.");
if (!ht) {
return;
}
- cds_lfht_for_each_entry(ht->ht, &iter.iter, ksyscall, node.node) {
- int ret;
-
- ret = lttng_ht_del(ht, &iter);
+ for (auto *ksyscall : lttng::urcu::lfht_iteration_adapter<struct syscall,
+ decltype(syscall::node),
+ &syscall::node>(*ht->ht)) {
+ const auto ret = cds_lfht_del(ht->ht, &ksyscall->node.node);
LTTNG_ASSERT(!ret);
- free(ksyscall);
+ delete ksyscall;
}
+
lttng_ht_destroy(ht);
}
/*
* Lookup a syscall in the given hash table by name.
*
+ * RCU read lock MUST be acquired by the callers of this function.
+ *
* Return syscall object if found or else NULL.
*/
static struct syscall *lookup_syscall(struct lttng_ht *ht, const char *name)
{
struct lttng_ht_node_str *node;
struct lttng_ht_iter iter;
- struct syscall *ksyscall = NULL;
+ struct syscall *ksyscall = nullptr;
LTTNG_ASSERT(ht);
LTTNG_ASSERT(name);
lttng_ht_lookup(ht, (void *) name, &iter);
- node = lttng_ht_iter_get_node_str(&iter);
+ node = lttng_ht_iter_get_node<lttng_ht_node_str>(&iter);
if (node) {
- ksyscall = caa_container_of(node, struct syscall, node);
+ ksyscall = lttng::utils::container_of(node, &syscall::node);
}
return ksyscall;
* syscall at index in the syscall table.
*/
static void update_event_syscall_bitness(struct lttng_event *events,
- unsigned int index, unsigned int syscall_index)
+ unsigned int index,
+ unsigned int syscall_index)
{
LTTNG_ASSERT(events);
if (syscall_table[index].bitness == 32) {
- events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags | LTTNG_EVENT_FLAG_SYSCALL_32);
+ events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags |
+ LTTNG_EVENT_FLAG_SYSCALL_32);
} else {
- events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags | LTTNG_EVENT_FLAG_SYSCALL_64);
+ events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags |
+ LTTNG_EVENT_FLAG_SYSCALL_64);
}
}
*
* Return 0 on success else -LTTNG_ERR_NOMEM.
*/
-static int add_syscall_to_ht(struct lttng_ht *ht, unsigned int index,
- unsigned int syscall_index)
+static int add_syscall_to_ht(struct lttng_ht *ht, unsigned int index, unsigned int syscall_index)
{
int ret;
struct syscall *ksyscall;
LTTNG_ASSERT(ht);
- ksyscall = (struct syscall *) zmalloc(sizeof(*ksyscall));
- if (!ksyscall) {
+ try {
+ ksyscall = new struct syscall(
+ syscall_index, syscall_table[index].bitness, syscall_table[index].name);
+ } catch (const std::bad_alloc& ex) {
+ ERR_FMT("Failed to allocate syscall entry when adding it to the global syscall hash table: syscall name=`{}`",
+ syscall_table[index].name);
ret = -LTTNG_ERR_NOMEM;
goto error;
}
- strncpy(ksyscall->name, syscall_table[index].name,
- sizeof(ksyscall->name));
- ksyscall->bitness = syscall_table[index].bitness;
- ksyscall->index = syscall_index;
- lttng_ht_node_init_str(&ksyscall->node, ksyscall->name);
lttng_ht_add_unique_str(ht, &ksyscall->node);
ret = 0;
ssize_t ret;
struct lttng_event *events;
/* Hash table used to filter duplicate out. */
- struct lttng_ht *syscalls_ht = NULL;
+ struct lttng_ht *syscalls_ht = nullptr;
LTTNG_ASSERT(_events);
DBG("Syscall table listing.");
- rcu_read_lock();
-
/*
* Allocate at least the number of total syscall we have even if some of
* them might not be valid. The count below will make sure to return the
* right size of the events array.
*/
- events = (lttng_event *) zmalloc(syscall_table_nb_entry * sizeof(*events));
+ events = calloc<lttng_event>(syscall_table.size());
if (!events) {
PERROR("syscall table list zmalloc");
ret = -LTTNG_ERR_NOMEM;
goto error;
}
- for (i = 0; i < syscall_table_nb_entry; i++) {
- struct syscall *ksyscall;
-
+ for (i = 0; i < syscall_table.size(); i++) {
/* Skip empty syscalls. */
if (*syscall_table[i].name == '\0') {
continue;
}
- ksyscall = lookup_syscall(syscalls_ht, syscall_table[i].name);
- if (ksyscall) {
- update_event_syscall_bitness(events, i, ksyscall->index);
- continue;
+ {
+ const lttng::urcu::read_lock_guard read_lock;
+ struct syscall *ksyscall;
+
+ ksyscall = lookup_syscall(syscalls_ht, syscall_table[i].name);
+ if (ksyscall) {
+ update_event_syscall_bitness(events, i, ksyscall->index);
+ continue;
+ }
}
ret = add_syscall_to_ht(syscalls_ht, i, index);
}
/* Copy the event information in the event's array. */
- strncpy(events[index].name, syscall_table[i].name,
- sizeof(events[index].name));
+ strncpy(events[index].name, syscall_table[i].name, sizeof(events[index].name));
update_event_syscall_bitness(events, i, index);
events[index].type = LTTNG_EVENT_SYSCALL;
/* This makes the command line not print the enabled/disabled field. */
destroy_syscall_ht(syscalls_ht);
*_events = events;
- rcu_read_unlock();
return index;
error:
destroy_syscall_ht(syscalls_ht);
free(events);
- rcu_read_unlock();
return ret;
}