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 <asm/bitsperlong.h>
11 #include <linux/compiler.h>
12 #include <linux/kernel.h>
13 #include <linux/zalloc.h>
14 
15 #include <string.h>
16 #include "string2.h"
17 
18 #include "trace/beauty/generated/syscalltbl.c"
19 
find_table(int e_machine)20 static const struct syscalltbl *find_table(int e_machine)
21 {
22 	static const struct syscalltbl *last_table;
23 	static int last_table_machine = EM_NONE;
24 
25 	/* Tables only exist for EM_SPARC. */
26 	if (e_machine == EM_SPARCV9)
27 		e_machine = EM_SPARC;
28 
29 	if (last_table_machine == e_machine && last_table != NULL)
30 		return last_table;
31 
32 	for (size_t i = 0; i < ARRAY_SIZE(syscalltbls); i++) {
33 		const struct syscalltbl *entry = &syscalltbls[i];
34 
35 		if (entry->e_machine != e_machine && entry->e_machine != EM_NONE)
36 			continue;
37 
38 		last_table = entry;
39 		last_table_machine = e_machine;
40 		return entry;
41 	}
42 	return NULL;
43 }
44 
syscalltbl__name(int e_machine,int id)45 const char *syscalltbl__name(int e_machine, int id)
46 {
47 	const struct syscalltbl *table = find_table(e_machine);
48 
49 	if (e_machine == EM_MIPS && id > 1000) {
50 		/*
51 		 * MIPS may encode the N32/64/O32 type in the high part of
52 		 * syscall number. Mask this off if present. See the values of
53 		 * __NR_N32_Linux, __NR_64_Linux, __NR_O32_Linux and __NR_Linux.
54 		 */
55 		id = id % 1000;
56 	}
57 	if (table && id >= 0 && id < table->num_to_name_len)
58 		return table->num_to_name[id];
59 	return NULL;
60 }
61 
62 struct syscall_cmp_key {
63 	const char *name;
64 	const char *const *tbl;
65 };
66 
syscallcmpname(const void * vkey,const void * ventry)67 static int syscallcmpname(const void *vkey, const void *ventry)
68 {
69 	const struct syscall_cmp_key *key = vkey;
70 	const uint16_t *entry = ventry;
71 
72 	return strcmp(key->name, key->tbl[*entry]);
73 }
74 
syscalltbl__id(int e_machine,const char * name)75 int syscalltbl__id(int e_machine, const char *name)
76 {
77 	const struct syscalltbl *table = find_table(e_machine);
78 	struct syscall_cmp_key key;
79 	const uint16_t *id;
80 
81 	if (!table)
82 		return -1;
83 
84 	key.name = name;
85 	key.tbl = table->num_to_name;
86 	id = bsearch(&key, table->sorted_names, table->sorted_names_len,
87 		     sizeof(table->sorted_names[0]), syscallcmpname);
88 
89 	return id ? *id : -1;
90 }
91 
syscalltbl__num_idx(int e_machine)92 int syscalltbl__num_idx(int e_machine)
93 {
94 	const struct syscalltbl *table = find_table(e_machine);
95 
96 	if (!table)
97 		return 0;
98 
99 	return table->sorted_names_len;
100 }
101 
syscalltbl__id_at_idx(int e_machine,int idx)102 int syscalltbl__id_at_idx(int e_machine, int idx)
103 {
104 	const struct syscalltbl *table = find_table(e_machine);
105 
106 	if (!table)
107 		return -1;
108 
109 	assert(idx >= 0 && idx < table->sorted_names_len);
110 	return table->sorted_names[idx];
111 }
112 
syscalltbl__strglobmatch_next(int e_machine,const char * syscall_glob,int * idx)113 int syscalltbl__strglobmatch_next(int e_machine, const char *syscall_glob, int *idx)
114 {
115 	const struct syscalltbl *table = find_table(e_machine);
116 
117 	for (int i = *idx + 1; table && i < table->sorted_names_len; ++i) {
118 		const char *name = table->num_to_name[table->sorted_names[i]];
119 
120 		if (strglobmatch(name, syscall_glob)) {
121 			*idx = i;
122 			return table->sorted_names[i];
123 		}
124 	}
125 
126 	return -1;
127 }
128 
syscalltbl__strglobmatch_first(int e_machine,const char * syscall_glob,int * idx)129 int syscalltbl__strglobmatch_first(int e_machine, const char *syscall_glob, int *idx)
130 {
131 	*idx = -1;
132 	return syscalltbl__strglobmatch_next(e_machine, syscall_glob, idx);
133 }
134