1 // gensyscalls.cpp 2 3 #include <cstdio> 4 #include <cstdlib> 5 #include <fstream> 6 #include <string> 7 8 #include "arch_config.h" 9 10 #include "gensyscalls.h" 11 #include "gensyscalls_common.h" 12 13 extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count); 14 15 // usage 16 const char *kUsage = 17 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ] [ -n <numbers> ]\n" 18 " [ -t <table> ] [ -s <strace> ]\n" 19 "\n" 20 "The command is able to generate several syscalls related source files.\n" 21 "\n" 22 " <calls> - Output: The assembly source file implementing the\n" 23 " actual syscalls.\n" 24 " <dispatcher> - Output: The C source file to be included by the\n" 25 " syscall dispatcher source file.\n" 26 " <numbers> - Output: The C/assembly include files defining the\n" 27 " syscall numbers.\n" 28 " <table> - Output: A C source file containing an array with\n" 29 " infos about the syscalls\n" 30 " <strace> - Output: A C source file for strace support.\n" 31 ; 32 33 // print_usage 34 static 35 void 36 print_usage(bool error) 37 { 38 fprintf((error ? stderr : stdout), kUsage); 39 } 40 41 enum { 42 PARAMETER_ALIGNMENT = sizeof(FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE) 43 }; 44 45 // Main 46 class Main { 47 public: 48 49 int Run(int argc, char **argv) 50 { 51 // parse arguments 52 const char *syscallsFile = NULL; 53 const char *dispatcherFile = NULL; 54 const char *numbersFile = NULL; 55 const char *tableFile = NULL; 56 const char *straceFile = NULL; 57 for (int argi = 1; argi < argc; argi++) { 58 string arg(argv[argi]); 59 if (arg == "-h" || arg == "--help") { 60 print_usage(false); 61 return 0; 62 } else if (arg == "-c") { 63 if (argi + 1 >= argc) { 64 print_usage(true); 65 return 1; 66 } 67 syscallsFile = argv[++argi]; 68 } else if (arg == "-d") { 69 if (argi + 1 >= argc) { 70 print_usage(true); 71 return 1; 72 } 73 dispatcherFile = argv[++argi]; 74 } else if (arg == "-n") { 75 if (argi + 1 >= argc) { 76 print_usage(true); 77 return 1; 78 } 79 numbersFile = argv[++argi]; 80 } else if (arg == "-t") { 81 if (argi + 1 >= argc) { 82 print_usage(true); 83 return 1; 84 } 85 tableFile = argv[++argi]; 86 } else if (arg == "-s") { 87 if (argi + 1 >= argc) { 88 print_usage(true); 89 return 1; 90 } 91 straceFile = argv[++argi]; 92 } else { 93 print_usage(true); 94 return 1; 95 } 96 } 97 fSyscallInfos = gensyscall_get_infos(&fSyscallCount); 98 _UpdateSyscallInfos(); 99 if (!syscallsFile && !dispatcherFile && !numbersFile && !tableFile 100 && !straceFile) { 101 printf("Found %d syscalls.\n", fSyscallCount); 102 return 0; 103 } 104 // generate the output 105 if (syscallsFile) 106 _WriteSyscallsFile(syscallsFile); 107 if (dispatcherFile) 108 _WriteDispatcherFile(dispatcherFile); 109 if (numbersFile) 110 _WriteNumbersFile(numbersFile); 111 if (tableFile) 112 _WriteTableFile(tableFile); 113 if (straceFile) 114 _WriteSTraceFile(straceFile); 115 return 0; 116 } 117 118 void _WriteSyscallsFile(const char *filename) 119 { 120 // open the syscalls output file 121 ofstream file(filename, ofstream::out | ofstream::trunc); 122 if (!file.is_open()) 123 throw IOException(string("Failed to open `") + filename + "'."); 124 // output the syscalls definitions 125 for (int i = 0; i < fSyscallCount; i++) { 126 const gensyscall_syscall_info &syscall = fSyscallInfos[i]; 127 int paramCount = syscall.parameter_count; 128 int paramSize = 0; 129 gensyscall_parameter_info* parameters = syscall.parameters; 130 // XXX: Currently the SYSCALL macros support 4 byte aligned 131 // parameters only. This has to change, of course. 132 for (int k = 0; k < paramCount; k++) { 133 int size = parameters[k].actual_size; 134 paramSize += (size + 3) / 4 * 4; 135 } 136 file << "SYSCALL" << (paramSize / 4) << "(" 137 << syscall.name << ", " << i << ")" << endl; 138 } 139 } 140 141 void _WriteDispatcherFile(const char *filename) 142 { 143 // open the dispatcher output file 144 ofstream file(filename, ofstream::out | ofstream::trunc); 145 if (!file.is_open()) 146 throw IOException(string("Failed to open `") + filename + "'."); 147 // output the case statements 148 for (int i = 0; i < fSyscallCount; i++) { 149 const gensyscall_syscall_info &syscall = fSyscallInfos[i]; 150 file << "case " << i << ":" << endl; 151 file << "\t"; 152 if (string(syscall.return_type) != "void") 153 file << "*call_ret = "; 154 file << syscall.kernel_name << "("; 155 int paramCount = syscall.parameter_count; 156 if (paramCount > 0) { 157 gensyscall_parameter_info* parameters = syscall.parameters; 158 if (parameters[0].size < PARAMETER_ALIGNMENT) { 159 file << "(" << parameters[0].type << ")*(" 160 << "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE" 161 << "*)args"; 162 } else { 163 file << "*(" << _GetPointerType(parameters[0].type) 164 << ")args"; 165 } 166 for (int k = 1; k < paramCount; k++) { 167 if (parameters[k].size < PARAMETER_ALIGNMENT) { 168 file << ", (" << parameters[k].type << ")*(" 169 << "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE" 170 << "*)((char*)args + " << parameters[k].offset 171 << ")"; 172 } else { 173 file << ", *(" << _GetPointerType(parameters[k].type) 174 << ")((char*)args + " << parameters[k].offset 175 << ")"; 176 } 177 } 178 } 179 file << ");" << endl; 180 file << "\tbreak;" << endl; 181 } 182 } 183 184 void _WriteNumbersFile(const char *filename) 185 { 186 // open the syscall numbers output file 187 ofstream file(filename, ofstream::out | ofstream::trunc); 188 if (!file.is_open()) 189 throw IOException(string("Failed to open `") + filename + "'."); 190 // output the defines 191 const char *prefix = "_user_"; 192 size_t prefixLen = strlen(prefix); 193 for (int i = 0; i < fSyscallCount; i++) { 194 const gensyscall_syscall_info &syscall = fSyscallInfos[i]; 195 string name(syscall.kernel_name); 196 // drop the leading "_user_" prefix 197 if (name.find(prefix) != 0) 198 throw Exception(string("Bad kernel name: `") + name + "'."); 199 name = string(name, prefixLen); 200 // convert to upper case (is there no function for that?) 201 string defineName; 202 for (int k = 0; k < (int)name.length(); k++) 203 defineName += toupper(name[k]); 204 file << "#define SYSCALL_" << defineName << " " << i << endl; 205 } 206 } 207 208 void _WriteTableFile(const char *filename) 209 { 210 // open the syscall table output file 211 ofstream file(filename, ofstream::out | ofstream::trunc); 212 if (!file.is_open()) 213 throw IOException(string("Failed to open `") + filename + "'."); 214 215 // output syscall count 216 file << "const int kSyscallCount = " << fSyscallCount << ";" << endl; 217 file << endl; 218 219 // syscall infos array preamble 220 file << "const syscall_info kSyscallInfos[] = {" << endl; 221 222 // the syscall infos 223 for (int i = 0; i < fSyscallCount; i++) { 224 const gensyscall_syscall_info &syscall = fSyscallInfos[i]; 225 226 // get the parameter size 227 int paramSize = 0; 228 if (syscall.parameter_count > 0) { 229 const gensyscall_parameter_info &lastParam 230 = syscall.parameters[syscall.parameter_count - 1]; 231 paramSize = lastParam.offset + lastParam.actual_size; 232 } 233 234 // output the info for the syscall 235 file << "\t{ " << syscall.kernel_name << ", " 236 << paramSize << " }," << endl; 237 } 238 239 // syscall infos array end 240 file << "};" << endl; 241 } 242 243 void _WriteSTraceFile(const char *filename) 244 { 245 // open the syscall table output file 246 ofstream file(filename, ofstream::out | ofstream::trunc); 247 if (!file.is_open()) 248 throw IOException(string("Failed to open `") + filename + "'."); 249 250 // the file defines a single function get_syscalls 251 file << "void" << endl 252 << "GET_SYSCALLS(vector<Syscall*> &syscalls)" << endl 253 << "{" << endl 254 << "\tSyscall *syscall;" << endl 255 << "\tTypeHandler *handler;" << endl 256 << "(void)syscall;" << endl 257 << "(void)handler;" << endl; 258 259 int chunkSize = (fSyscallCount + 19) / 20; 260 261 // iterate through the syscalls 262 for (int i = 0; i < fSyscallCount; i++) { 263 const gensyscall_syscall_info &syscall = fSyscallInfos[i]; 264 265 if (i % chunkSize == 0) { 266 // chunk end 267 file << endl; 268 if (i > 0) 269 file << "#endif" << endl; 270 // chunk begin 271 file << "#ifdef SYSCALLS_CHUNK_" << (i / chunkSize) << endl; 272 } 273 274 // spacing, comment 275 file << endl; 276 file << "\t// " << syscall.name << endl; 277 278 // create the return type handler 279 file << "\thandler = TypeHandlerFactory<" << syscall.return_type 280 << ">::Create();" << endl; 281 282 // create the syscall 283 file << "\tsyscall = new Syscall(\"" << syscall.name << "\", " 284 << "\"" << syscall.return_type << "\", "<< "handler);" << endl; 285 file << "\tsyscalls.push_back(syscall);" << endl; 286 287 // add the parameters 288 for (int k = 0; k < syscall.parameter_count; k++) { 289 const gensyscall_parameter_info ¶meter 290 = syscall.parameters[k]; 291 292 // create the parameter type handler 293 file << "\thandler = TypeHandlerFactory<" 294 << parameter.type << ">::Create();" << endl; 295 296 // add the parameter 297 file << "\tsyscall->AddParameter(\"" << parameter.name << "\", " 298 << parameter.offset << ", \"" << parameter.type 299 << "\", handler);" << endl; 300 } 301 } 302 303 // last syscall chunk end 304 file << "#endif" << endl; 305 306 // function end 307 file << "}" << endl; 308 } 309 310 static string _GetPointerType(const char *type) 311 { 312 char *parenthesis = strchr(type, ')'); 313 if (!parenthesis) 314 return string(type) + "*"; 315 // function pointer type 316 return string(type, parenthesis - type) + "*" + parenthesis; 317 } 318 319 void _UpdateSyscallInfos() 320 { 321 // Since getting the parameter offsets and actual sizes doesn't work 322 // as it is now, we overwrite them with values computed using the 323 // parameter alignment type. 324 for (int i = 0; i < fSyscallCount; i++) { 325 gensyscall_syscall_info &syscall = fSyscallInfos[i]; 326 int paramCount = syscall.parameter_count; 327 gensyscall_parameter_info* parameters = syscall.parameters; 328 int offset = 0; 329 for (int k = 0; k < paramCount; k++) { 330 if (parameters[k].size < PARAMETER_ALIGNMENT) 331 parameters[k].actual_size = PARAMETER_ALIGNMENT; 332 else 333 parameters[k].actual_size = parameters[k].size; 334 parameters[k].offset = offset; 335 offset += parameters[k].actual_size; 336 } 337 } 338 } 339 340 private: 341 gensyscall_syscall_info *fSyscallInfos; 342 int fSyscallCount; 343 }; 344 345 // main 346 int 347 main(int argc, char **argv) 348 { 349 try { 350 return Main().Run(argc, argv); 351 } catch (Exception &exception) { 352 fprintf(stderr, "%s\n", exception.what()); 353 return 1; 354 } 355 } 356