xref: /linux/tools/perf/util/syscalltbl.c (revision cb8197db8c09d7e17a71821ce4076e13ac7f5c70)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * System call table mapper
4  *
5  * (C) 2016 Arnaldo Carvalho de Melo <acme@redhat.com>
6  */
7 
8 #include "syscalltbl.h"
9 #include <stdlib.h>
10 #include <linux/compiler.h>
11 #include <linux/zalloc.h>
12 
13 #ifdef HAVE_SYSCALL_TABLE_SUPPORT
14 #include <string.h>
15 #include "string2.h"
16 
17 #if defined(__s390x__)
18 #include <asm/syscalls_64.c>
19 const int syscalltbl_native_max_id = SYSCALLTBL_S390_64_MAX_ID;
20 static const char *const *syscalltbl_native = syscalltbl_s390_64;
21 #elif defined(__powerpc64__)
22 #include <asm/syscalls_64.c>
23 const int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_64_MAX_ID;
24 static const char *const *syscalltbl_native = syscalltbl_powerpc_64;
25 #elif defined(__powerpc__)
26 #include <asm/syscalls_32.c>
27 const int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_32_MAX_ID;
28 static const char *const *syscalltbl_native = syscalltbl_powerpc_32;
29 #elif defined(__mips__)
30 #include <asm/syscalls_n64.c>
31 const int syscalltbl_native_max_id = SYSCALLTBL_MIPS_N64_MAX_ID;
32 static const char *const *syscalltbl_native = syscalltbl_mips_n64;
33 #elif defined(__loongarch__)
34 #include <asm/syscalls.c>
35 const int syscalltbl_native_max_id = SYSCALLTBL_LOONGARCH_MAX_ID;
36 static const char *const *syscalltbl_native = syscalltbl_loongarch;
37 #elif defined(GENERIC_SYSCALL_TABLE)
38 #include <syscall_table.h>
39 const int syscalltbl_native_max_id = SYSCALLTBL_MAX_ID;
40 static const char *const *syscalltbl_native = syscalltbl;
41 #else
42 const int syscalltbl_native_max_id = 0;
43 static const char *const syscalltbl_native[] = {
44 	[0] = "unknown",
45 };
46 #endif
47 
48 struct syscall {
49 	int id;
50 	const char *name;
51 };
52 
53 static int syscallcmpname(const void *vkey, const void *ventry)
54 {
55 	const char *key = vkey;
56 	const struct syscall *entry = ventry;
57 
58 	return strcmp(key, entry->name);
59 }
60 
61 static int syscallcmp(const void *va, const void *vb)
62 {
63 	const struct syscall *a = va, *b = vb;
64 
65 	return strcmp(a->name, b->name);
66 }
67 
68 static int syscalltbl__init_native(struct syscalltbl *tbl)
69 {
70 	int nr_entries = 0, i, j;
71 	struct syscall *entries;
72 
73 	for (i = 0; i <= syscalltbl_native_max_id; ++i)
74 		if (syscalltbl_native[i])
75 			++nr_entries;
76 
77 	entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries);
78 	if (tbl->syscalls.entries == NULL)
79 		return -1;
80 
81 	for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) {
82 		if (syscalltbl_native[i]) {
83 			entries[j].name = syscalltbl_native[i];
84 			entries[j].id = i;
85 			++j;
86 		}
87 	}
88 
89 	qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp);
90 	tbl->syscalls.nr_entries = nr_entries;
91 	tbl->syscalls.max_id	 = syscalltbl_native_max_id;
92 	return 0;
93 }
94 
95 struct syscalltbl *syscalltbl__new(void)
96 {
97 	struct syscalltbl *tbl = malloc(sizeof(*tbl));
98 	if (tbl) {
99 		if (syscalltbl__init_native(tbl)) {
100 			free(tbl);
101 			return NULL;
102 		}
103 	}
104 	return tbl;
105 }
106 
107 void syscalltbl__delete(struct syscalltbl *tbl)
108 {
109 	zfree(&tbl->syscalls.entries);
110 	free(tbl);
111 }
112 
113 const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id)
114 {
115 	return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL;
116 }
117 
118 int syscalltbl__id(struct syscalltbl *tbl, const char *name)
119 {
120 	struct syscall *sc = bsearch(name, tbl->syscalls.entries,
121 				     tbl->syscalls.nr_entries, sizeof(*sc),
122 				     syscallcmpname);
123 
124 	return sc ? sc->id : -1;
125 }
126 
127 int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx)
128 {
129 	struct syscall *syscalls = tbl->syscalls.entries;
130 
131 	return idx < tbl->syscalls.nr_entries ? syscalls[idx].id : -1;
132 }
133 
134 int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
135 {
136 	int i;
137 	struct syscall *syscalls = tbl->syscalls.entries;
138 
139 	for (i = *idx + 1; i < tbl->syscalls.nr_entries; ++i) {
140 		if (strglobmatch(syscalls[i].name, syscall_glob)) {
141 			*idx = i;
142 			return syscalls[i].id;
143 		}
144 	}
145 
146 	return -1;
147 }
148 
149 int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
150 {
151 	*idx = -1;
152 	return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx);
153 }
154 
155 #else /* HAVE_SYSCALL_TABLE_SUPPORT */
156 
157 #include <libaudit.h>
158 
159 struct syscalltbl *syscalltbl__new(void)
160 {
161 	struct syscalltbl *tbl = zalloc(sizeof(*tbl));
162 	if (tbl)
163 		tbl->audit_machine = audit_detect_machine();
164 	return tbl;
165 }
166 
167 void syscalltbl__delete(struct syscalltbl *tbl)
168 {
169 	free(tbl);
170 }
171 
172 const char *syscalltbl__name(const struct syscalltbl *tbl, int id)
173 {
174 	return audit_syscall_to_name(id, tbl->audit_machine);
175 }
176 
177 int syscalltbl__id(struct syscalltbl *tbl, const char *name)
178 {
179 	return audit_name_to_syscall(name, tbl->audit_machine);
180 }
181 
182 int syscalltbl__id_at_idx(struct syscalltbl *tbl __maybe_unused, int idx)
183 {
184 	return idx;
185 }
186 
187 int syscalltbl__strglobmatch_next(struct syscalltbl *tbl __maybe_unused,
188 				  const char *syscall_glob __maybe_unused, int *idx __maybe_unused)
189 {
190 	return -1;
191 }
192 
193 int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
194 {
195 	return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx);
196 }
197 #endif /* HAVE_SYSCALL_TABLE_SUPPORT */
198