Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng-sessiond / lttng-syscall.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2014 David Goulet <dgoulet@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8#define _LGPL_SOURCE
9#include "kernel.hpp"
10#include "lttng-sessiond.hpp"
11#include "lttng-syscall.hpp"
12#include "utils.hpp"
13
14#include <common/common.hpp>
15#include <common/kernel-ctl/kernel-ctl.hpp>
16#include <common/urcu.hpp>
17
18#include <stdbool.h>
19
20/* Global syscall table. */
21std::vector<struct syscall> syscall_table;
22
23/*
24 * Populate the system call table using the kernel tracer.
25 *
26 * Return 0 on success and the syscall table is allocated. On error, a negative
27 * value is returned.
28 */
29int syscall_init_table(int tracer_fd)
30{
31 int ret, fd, err;
32 FILE *fp;
33 /* Syscall data from the kernel. */
34 size_t index = 0;
35 uint32_t bitness;
36 char name[SYSCALL_NAME_LEN];
37
38#if (SYSCALL_NAME_LEN == 255)
39#define SYSCALL_NAME_LEN_SCANF_IS_A_BROKEN_API "254"
40#endif
41
42 DBG3("Syscall init system call table");
43
44 fd = kernctl_syscall_list(tracer_fd);
45 if (fd < 0) {
46 ret = fd;
47 PERROR("kernelctl syscall list");
48 goto error_ioctl;
49 }
50
51 fp = fdopen(fd, "r");
52 if (!fp) {
53 ret = -errno;
54 PERROR("syscall list fdopen");
55 goto error_fp;
56 }
57
58 while (fscanf(fp,
59 "syscall { index = %zu; \
60 name = %" SYSCALL_NAME_LEN_SCANF_IS_A_BROKEN_API "[^;]; \
61 bitness = %u; };\n",
62 &index,
63 name,
64 &bitness) == 3) {
65 try {
66 syscall_table.emplace_back(index, bitness, name);
67 } catch (const std::bad_alloc&) {
68 ERR_FMT("Failed to add syscall to syscall table: table_current_element_count={}, syscall_name=`{}`",
69 syscall_table.size(),
70 name);
71 ret = ENOMEM;
72 goto error;
73 } catch (const lttng::invalid_argument_error& ex) {
74 ERR_FMT("Failed to add syscall to syscall table: table_current_element_count={}, reason=`{}`",
75 syscall_table.size(),
76 name,
77 ex.what());
78 ret = EINVAL;
79 goto error;
80 }
81 }
82
83 ret = 0;
84
85error:
86 err = fclose(fp);
87 if (err) {
88 PERROR("syscall list fclose");
89 }
90 return ret;
91
92error_fp:
93 err = close(fd);
94 if (err) {
95 PERROR("syscall list close");
96 }
97
98error_ioctl:
99 return ret;
100}
101
102/*
103 * Helper function for the list syscalls command that empty the temporary
104 * syscall hashtable used to track duplicate between 32 and 64 bit arch.
105 *
106 * This empty the hash table and destroys it after. After this, the pointer is
107 * unsuable. RCU read side lock MUST NOT be acquired before calling this.
108 */
109static void destroy_syscall_ht(struct lttng_ht *ht)
110{
111 DBG3("Destroying syscall hash table.");
112
113 if (!ht) {
114 return;
115 }
116
117 for (auto *ksyscall : lttng::urcu::lfht_iteration_adapter<struct syscall,
118 decltype(syscall::node),
119 &syscall::node>(*ht->ht)) {
120 const auto ret = cds_lfht_del(ht->ht, &ksyscall->node.node);
121 LTTNG_ASSERT(!ret);
122 delete ksyscall;
123 }
124
125 lttng_ht_destroy(ht);
126}
127
128/*
129 * Allocate the given hashtable pointer.
130 *
131 * Return 0 on success else a negative LTTNG error value.
132 */
133static int init_syscall_ht(struct lttng_ht **ht)
134{
135 int ret;
136
137 *ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
138 if (!*ht) {
139 ret = -LTTNG_ERR_NOMEM;
140 } else {
141 ret = 0;
142 }
143
144 return ret;
145}
146
147/*
148 * Lookup a syscall in the given hash table by name.
149 *
150 * RCU read lock MUST be acquired by the callers of this function.
151 *
152 * Return syscall object if found or else NULL.
153 */
154static struct syscall *lookup_syscall(struct lttng_ht *ht, const char *name)
155{
156 struct lttng_ht_node_str *node;
157 struct lttng_ht_iter iter;
158 struct syscall *ksyscall = nullptr;
159
160 LTTNG_ASSERT(ht);
161 LTTNG_ASSERT(name);
162
163 lttng_ht_lookup(ht, (void *) name, &iter);
164 node = lttng_ht_iter_get_node<lttng_ht_node_str>(&iter);
165 if (node) {
166 ksyscall = lttng::utils::container_of(node, &syscall::node);
167 }
168
169 return ksyscall;
170}
171
172/*
173 * Using the given syscall object in the events array with the bitness of the
174 * syscall at index in the syscall table.
175 */
176static void update_event_syscall_bitness(struct lttng_event *events,
177 unsigned int index,
178 unsigned int syscall_index)
179{
180 LTTNG_ASSERT(events);
181
182 if (syscall_table[index].bitness == 32) {
183 events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags |
184 LTTNG_EVENT_FLAG_SYSCALL_32);
185 } else {
186 events[syscall_index].flags = (lttng_event_flag) (events[syscall_index].flags |
187 LTTNG_EVENT_FLAG_SYSCALL_64);
188 }
189}
190
191/*
192 * Allocate and initialize syscall object and add it to the given hashtable.
193 *
194 * Return 0 on success else -LTTNG_ERR_NOMEM.
195 */
196static int add_syscall_to_ht(struct lttng_ht *ht, unsigned int index, unsigned int syscall_index)
197{
198 int ret;
199 struct syscall *ksyscall;
200
201 LTTNG_ASSERT(ht);
202
203 try {
204 ksyscall = new struct syscall(
205 syscall_index, syscall_table[index].bitness, syscall_table[index].name);
206 } catch (const std::bad_alloc& ex) {
207 ERR_FMT("Failed to allocate syscall entry when adding it to the global syscall hash table: syscall name=`{}`",
208 syscall_table[index].name);
209 ret = -LTTNG_ERR_NOMEM;
210 goto error;
211 }
212
213 lttng_ht_add_unique_str(ht, &ksyscall->node);
214 ret = 0;
215
216error:
217 return ret;
218}
219
220/*
221 * List syscalls present in the kernel syscall global array, allocate and
222 * populate the events structure with them. Skip the empty syscall name.
223 *
224 * Return the number of entries in the array else a negative value.
225 */
226ssize_t syscall_table_list(struct lttng_event **_events)
227{
228 int i, index = 0;
229 ssize_t ret;
230 struct lttng_event *events;
231 /* Hash table used to filter duplicate out. */
232 struct lttng_ht *syscalls_ht = nullptr;
233
234 LTTNG_ASSERT(_events);
235
236 DBG("Syscall table listing.");
237
238 /*
239 * Allocate at least the number of total syscall we have even if some of
240 * them might not be valid. The count below will make sure to return the
241 * right size of the events array.
242 */
243 events = calloc<lttng_event>(syscall_table.size());
244 if (!events) {
245 PERROR("syscall table list zmalloc");
246 ret = -LTTNG_ERR_NOMEM;
247 goto error;
248 }
249
250 ret = init_syscall_ht(&syscalls_ht);
251 if (ret < 0) {
252 goto error;
253 }
254
255 for (i = 0; i < syscall_table.size(); i++) {
256 /* Skip empty syscalls. */
257 if (*syscall_table[i].name == '\0') {
258 continue;
259 }
260
261 {
262 const lttng::urcu::read_lock_guard read_lock;
263 struct syscall *ksyscall;
264
265 ksyscall = lookup_syscall(syscalls_ht, syscall_table[i].name);
266 if (ksyscall) {
267 update_event_syscall_bitness(events, i, ksyscall->index);
268 continue;
269 }
270 }
271
272 ret = add_syscall_to_ht(syscalls_ht, i, index);
273 if (ret < 0) {
274 goto error;
275 }
276
277 /* Copy the event information in the event's array. */
278 strncpy(events[index].name, syscall_table[i].name, sizeof(events[index].name));
279 update_event_syscall_bitness(events, i, index);
280 events[index].type = LTTNG_EVENT_SYSCALL;
281 /* This makes the command line not print the enabled/disabled field. */
282 events[index].enabled = -1;
283 index++;
284 }
285
286 destroy_syscall_ht(syscalls_ht);
287 *_events = events;
288 return index;
289
290error:
291 destroy_syscall_ht(syscalls_ht);
292 free(events);
293 return ret;
294}
This page took 0.024961 seconds and 5 git commands to generate.