xref: /haiku/src/tools/gensyscalls/gensyscalls.cpp (revision 91a479693905981194510c2bf8a6e166a62ce4c9)
1 // gensyscalls.cpp
2 
3 #include <cstdio>
4 #include <cstdlib>
5 #include <fstream>
6 #include <string>
7 #include <inttypes.h>
8 
9 #include "arch_config.h"
10 
11 #include "gensyscalls.h"
12 #include "gensyscalls_common.h"
13 
14 extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count);
15 
16 // usage
17 const char *kUsage =
18 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ]\n"
19 "\n"
20 "The command generates a piece of assembly source file that defines the\n"
21 "actual syscalls and a piece of C source (cases of a switch statement) for"
22 "the kernel syscall dispatcher. Either file is to be included from a"
23 "respective skeleton source file.\n"
24 "\n"
25 "  <calls>                - Output: The assembly source file implementing the\n"
26 "                           actual syscalls."
27 "  <dispatcher>           - Output: The C source file to be included by the\n"
28 "                           syscall dispatcher source file.\n";
29 
30 // print_usage
31 static
32 void
33 print_usage(bool error)
34 {
35 	fprintf((error ? stderr : stdout), kUsage);
36 }
37 
38 enum {
39 	PARAMETER_ALIGNMENT	= sizeof(FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE)
40 };
41 
42 // Main
43 class Main {
44 public:
45 
46 	int Run(int argc, char **argv)
47 	{
48 		// parse arguments
49 		const char *syscallsFile = NULL;
50 		const char *dispatcherFile = NULL;
51 		for (int argi = 1; argi < argc; argi++) {
52 			string arg(argv[argi]);
53 			if (arg == "-h" || arg == "--help") {
54 				print_usage(false);
55 				return 0;
56 			} else if (arg == "-c") {
57 				if (argi + 1 >= argc) {
58 					print_usage(true);
59 					return 1;
60 				}
61 				syscallsFile = argv[++argi];
62 			} else if (arg == "-d") {
63 				if (argi + 1 >= argc) {
64 					print_usage(true);
65 					return 1;
66 				}
67 				dispatcherFile = argv[++argi];
68 			} else {
69 				print_usage(true);
70 				return 1;
71 			}
72 		}
73 		fSyscallInfos = gensyscall_get_infos(&fSyscallCount);
74 		_UpdateSyscallInfos();
75 		if (!syscallsFile && !dispatcherFile) {
76 			printf("Found %d syscalls.\n", fSyscallCount);
77 			return 0;
78 		}
79 		// generate the output
80 		if (syscallsFile)
81 			_WriteSyscallsFile(syscallsFile);
82 		if (dispatcherFile)
83 			_WriteDispatcherFile(dispatcherFile);
84 		return 0;
85 	}
86 
87 	void _WriteSyscallsFile(const char *filename)
88 	{
89 		// open the syscalls output file
90 		ofstream file(filename, ofstream::out | ofstream::trunc);
91 		if (!file.is_open())
92 			throw IOException(string("Failed to open `") + filename + "'.");
93 		// output the syscalls definitions
94 		for (int i = 0; i < fSyscallCount; i++) {
95 			const gensyscall_syscall_info &syscall = fSyscallInfos[i];
96 			int paramCount = syscall.parameter_count;
97 			int paramSize = 0;
98 			gensyscall_parameter_info* parameters = syscall.parameters;
99 			// XXX: Currently the SYSCALL macros support 4 byte aligned
100 			// parameters only. This has to change, of course.
101 			for (int k = 0; k < paramCount; k++) {
102 				int size = parameters[k].actual_size;
103 				paramSize += (size + 3) / 4 * 4;
104 			}
105 			file << "SYSCALL" << (paramSize / 4) << "("
106 				<< syscall.name << ", " << i << ")" << endl;
107 		}
108 	}
109 
110 	void _WriteDispatcherFile(const char *filename)
111 	{
112 		// open the dispatcher output file
113 		ofstream file(filename, ofstream::out | ofstream::trunc);
114 		if (!file.is_open())
115 			throw IOException(string("Failed to open `") + filename + "'.");
116 		// output the case statements
117 		for (int i = 0; i < fSyscallCount; i++) {
118 			const gensyscall_syscall_info &syscall = fSyscallInfos[i];
119 			file << "case " << i << ":" << endl;
120 			file << "\t";
121 			if (string(syscall.return_type) != "void")
122 				file << "*call_ret = ";
123 			file << syscall.kernel_name << "(";
124 			int paramCount = syscall.parameter_count;
125 			if (paramCount > 0) {
126 				gensyscall_parameter_info* parameters = syscall.parameters;
127 				if (parameters[0].size < PARAMETER_ALIGNMENT) {
128 					file << "(" << parameters[0].type << ")*("
129 						 << "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE"
130 						 << "*)args";
131 				} else {
132 					file << "*(" << _GetPointerType(parameters[0].type)
133 						<< ")args";
134 				}
135 				for (int k = 1; k < paramCount; k++) {
136 					if (parameters[k].size < PARAMETER_ALIGNMENT) {
137 						file << ", (" << parameters[k].type << ")*("
138 							<< "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE"
139 							<< "*)((char*)args + " << parameters[k].offset
140 							<< ")";
141 					} else {
142 						file << ", *(" << _GetPointerType(parameters[k].type)
143 							<< ")((char*)args + " << parameters[k].offset
144 							<< ")";
145 					}
146 				}
147 			}
148 			file << ");" << endl;
149 			file << "\tbreak;" << endl;
150 		}
151 	}
152 
153 	static string _GetPointerType(const char *type)
154 	{
155 		char *parenthesis = strchr(type, ')');
156 		if (!parenthesis)
157 			return string(type) + "*";
158 		// function pointer type
159 		return string(type, parenthesis - type) + "*" + parenthesis;
160 	}
161 
162 	void _UpdateSyscallInfos()
163 	{
164 		// Since getting the parameter offsets and actual sizes doesn't work
165 		// as it is now, we overwrite them with values computed using the
166 		// parameter alignment type.
167 		for (int i = 0; i < fSyscallCount; i++) {
168 			gensyscall_syscall_info &syscall = fSyscallInfos[i];
169 			int paramCount = syscall.parameter_count;
170 			gensyscall_parameter_info* parameters = syscall.parameters;
171 			int offset = 0;
172 			for (int k = 0; k < paramCount; k++) {
173 				if (parameters[k].size < PARAMETER_ALIGNMENT)
174 					parameters[k].actual_size = PARAMETER_ALIGNMENT;
175 				else
176 					parameters[k].actual_size = parameters[k].size;
177 				parameters[k].offset = offset;
178 				offset += parameters[k].actual_size;
179 			}
180 		}
181 	}
182 
183 private:
184 	gensyscall_syscall_info	*fSyscallInfos;
185 	int						fSyscallCount;
186 };
187 
188 // main
189 int
190 main(int argc, char **argv)
191 {
192 	try {
193 		return Main().Run(argc, argv);
194 	} catch (Exception &exception) {
195 		fprintf(stderr, "%s\n", exception.what());
196 		return 1;
197 	}
198 }
199