1 // gensyscalls.cpp 2 3 // Don't include arch_gensyscalls.h. It's only needed when creating the 4 // syscall vector. 5 #define DONT_INCLUDE_ARCH_GENSYSCALLS_H 1 6 7 #include <cstdio> 8 #include <cstdlib> 9 #include <fstream> 10 #include <string> 11 #include <vector> 12 13 #include "gensyscalls.h" 14 #include "gensyscalls_common.h" 15 16 using std::vector; 17 18 // usage 19 const char *kUsage = 20 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ] [ -n <numbers> ]\n" 21 " [ -t <table> ] [ -s <strace> ]\n" 22 "\n" 23 "The command is able to generate several syscalls related source files.\n" 24 "\n" 25 " <calls> - Output: The assembly source file implementing the\n" 26 " actual syscalls.\n" 27 " <dispatcher> - Output: The C source file to be included by the\n" 28 " syscall dispatcher source file.\n" 29 " <numbers> - Output: The C/assembly include files defining the\n" 30 " syscall numbers.\n" 31 " <table> - Output: A C source file containing an array with\n" 32 " infos about the syscalls\n" 33 " <strace> - Output: A C source file for strace support.\n" 34 ; 35 36 // print_usage 37 static 38 void 39 print_usage(bool error) 40 { 41 fprintf((error ? stderr : stdout), kUsage); 42 } 43 44 45 // Type 46 47 // constructor 48 Type::Type(const char* name, int size, int usedSize, 49 const char* alignmentTypeName) 50 : fName(name), 51 fSize(size), 52 fUsedSize(usedSize), 53 fAlignmentType(alignmentTypeName) 54 { 55 } 56 57 58 // Parameter 59 60 // constructor 61 Parameter::Parameter(const char* typeName, const char* parameterName, 62 int size, int usedSize, int offset, const char* alignmentTypeName) 63 : Type(typeName, size, usedSize, alignmentTypeName), 64 fParameterName(parameterName), 65 fOffset(offset) 66 { 67 } 68 69 70 // Syscall 71 72 // ParameterVector 73 struct Syscall::ParameterVector : public vector<Parameter*> { 74 }; 75 76 // constructor 77 Syscall::Syscall(const char* name, const char* kernelName) 78 : fName(name), 79 fKernelName(kernelName), 80 fReturnType(NULL), 81 fParameters(new ParameterVector) 82 { 83 } 84 85 // destructor 86 Syscall::~Syscall() 87 { 88 delete fReturnType; 89 90 int count = CountParameters(); 91 for (int i = 0; i < count; i++) 92 delete ParameterAt(i); 93 delete fParameters; 94 } 95 96 // ParameterAt 97 int 98 Syscall::CountParameters() const 99 { 100 return fParameters->size(); 101 } 102 103 // ParameterAt 104 Parameter* 105 Syscall::ParameterAt(int index) const 106 { 107 if (index < 0 || index >= CountParameters()) 108 return NULL; 109 110 return (*fParameters)[index]; 111 } 112 113 // LastParameter 114 Parameter* 115 Syscall::LastParameter() const 116 { 117 return ParameterAt(CountParameters() - 1); 118 } 119 120 // SetReturnType 121 Type* 122 Syscall::SetReturnType(const char* name, int size, int usedSize, 123 const char* alignmentTypeName) 124 { 125 delete fReturnType; 126 return fReturnType = new Type(name, size, usedSize, alignmentTypeName); 127 } 128 129 // AddParameter 130 Parameter* 131 Syscall::AddParameter(const char* typeName, const char* parameterName, 132 int size, int usedSize, int offset, const char* alignmentTypeName) 133 { 134 Parameter* parameter = new Parameter(typeName, parameterName, size, 135 usedSize, offset, alignmentTypeName); 136 fParameters->push_back(parameter); 137 return parameter; 138 } 139 140 141 // SyscallVector 142 143 struct SyscallVector::_SyscallVector : public vector<Syscall*> { 144 }; 145 146 147 // constructor 148 SyscallVector::SyscallVector() 149 : fSyscalls(new _SyscallVector) 150 { 151 } 152 153 // destructor 154 SyscallVector::~SyscallVector() 155 { 156 int count = CountSyscalls(); 157 for (int i = 0; i < count; i++) 158 delete SyscallAt(i); 159 delete fSyscalls; 160 } 161 162 // Create 163 SyscallVector* 164 SyscallVector::Create() 165 { 166 return new SyscallVector; 167 } 168 169 // CountSyscalls 170 int 171 SyscallVector::CountSyscalls() const 172 { 173 return fSyscalls->size(); 174 } 175 176 // SyscallAt 177 Syscall* 178 SyscallVector::SyscallAt(int index) const 179 { 180 if (index < 0 || index >= CountSyscalls()) 181 return NULL; 182 183 return (*fSyscalls)[index]; 184 } 185 186 // CreateSyscall 187 Syscall* 188 SyscallVector::CreateSyscall(const char* name, const char* kernelName) 189 { 190 Syscall* syscall = new Syscall(name, kernelName); 191 fSyscalls->push_back(syscall); 192 return syscall; 193 } 194 195 196 // #pragma mark - 197 198 // Main 199 class Main { 200 public: 201 202 int Run(int argc, char **argv) 203 { 204 // parse arguments 205 const char *syscallsFile = NULL; 206 const char *dispatcherFile = NULL; 207 const char *numbersFile = NULL; 208 const char *tableFile = NULL; 209 const char *straceFile = NULL; 210 for (int argi = 1; argi < argc; argi++) { 211 string arg(argv[argi]); 212 if (arg == "-h" || arg == "--help") { 213 print_usage(false); 214 return 0; 215 } else if (arg == "-c") { 216 if (argi + 1 >= argc) { 217 print_usage(true); 218 return 1; 219 } 220 syscallsFile = argv[++argi]; 221 } else if (arg == "-d") { 222 if (argi + 1 >= argc) { 223 print_usage(true); 224 return 1; 225 } 226 dispatcherFile = argv[++argi]; 227 } else if (arg == "-n") { 228 if (argi + 1 >= argc) { 229 print_usage(true); 230 return 1; 231 } 232 numbersFile = argv[++argi]; 233 } else if (arg == "-t") { 234 if (argi + 1 >= argc) { 235 print_usage(true); 236 return 1; 237 } 238 tableFile = argv[++argi]; 239 } else if (arg == "-s") { 240 if (argi + 1 >= argc) { 241 print_usage(true); 242 return 1; 243 } 244 straceFile = argv[++argi]; 245 } else { 246 print_usage(true); 247 return 1; 248 } 249 } 250 fSyscallVector = create_syscall_vector(); 251 fSyscallCount = fSyscallVector->CountSyscalls(); 252 if (!syscallsFile && !dispatcherFile && !numbersFile && !tableFile 253 && !straceFile) { 254 printf("Found %d syscalls.\n", fSyscallCount); 255 return 0; 256 } 257 // generate the output 258 if (syscallsFile) 259 _WriteSyscallsFile(syscallsFile); 260 if (dispatcherFile) 261 _WriteDispatcherFile(dispatcherFile); 262 if (numbersFile) 263 _WriteNumbersFile(numbersFile); 264 if (tableFile) 265 _WriteTableFile(tableFile); 266 if (straceFile) 267 _WriteSTraceFile(straceFile); 268 return 0; 269 } 270 271 void _WriteSyscallsFile(const char *filename) 272 { 273 // open the syscalls output file 274 ofstream file(filename, ofstream::out | ofstream::trunc); 275 if (!file.is_open()) 276 throw IOException(string("Failed to open `") + filename + "'."); 277 278 // output the syscalls definitions 279 for (int i = 0; i < fSyscallCount; i++) { 280 const Syscall* syscall = fSyscallVector->SyscallAt(i); 281 int paramCount = syscall->CountParameters(); 282 int paramSize = 0; 283 // XXX: Currently the SYSCALL macros support 4 byte aligned 284 // parameters only. This has to change, of course. 285 for (int k = 0; k < paramCount; k++) { 286 const Parameter* parameter = syscall->ParameterAt(k); 287 int size = parameter->UsedSize(); 288 paramSize += (size + 3) / 4 * 4; 289 } 290 file << "SYSCALL" << (paramSize / 4) << "(" 291 << syscall->Name() << ", " << i << ")" << endl; 292 } 293 } 294 295 void _WriteDispatcherFile(const char *filename) 296 { 297 // open the dispatcher output file 298 ofstream file(filename, ofstream::out | ofstream::trunc); 299 if (!file.is_open()) 300 throw IOException(string("Failed to open `") + filename + "'."); 301 302 // output the case statements 303 for (int i = 0; i < fSyscallCount; i++) { 304 const Syscall* syscall = fSyscallVector->SyscallAt(i); 305 file << "case " << i << ":" << endl; 306 file << "\t"; 307 if (string(syscall->ReturnType()->TypeName()) != "void") 308 file << "*call_ret = "; 309 file << syscall->KernelName() << "("; 310 int paramCount = syscall->CountParameters(); 311 if (paramCount > 0) { 312 Parameter* parameter = syscall->ParameterAt(0); 313 if (parameter->AlignmentTypeName()) { 314 file << "(" << parameter->TypeName() << ")*(" 315 << parameter->AlignmentTypeName() 316 << "*)args"; 317 } else { 318 file << "*(" << _GetPointerType(parameter->TypeName()) 319 << ")args"; 320 } 321 for (int k = 1; k < paramCount; k++) { 322 parameter = syscall->ParameterAt(k); 323 if (parameter->AlignmentTypeName()) { 324 file << ", (" << parameter->TypeName() << ")*(" 325 << parameter->AlignmentTypeName() 326 << "*)((char*)args + " << parameter->Offset() 327 << ")"; 328 } else { 329 file << ", *(" << _GetPointerType(parameter->TypeName()) 330 << ")((char*)args + " << parameter->Offset() 331 << ")"; 332 } 333 } 334 } 335 file << ");" << endl; 336 file << "\tbreak;" << endl; 337 } 338 } 339 340 void _WriteNumbersFile(const char *filename) 341 { 342 // open the syscall numbers output file 343 ofstream file(filename, ofstream::out | ofstream::trunc); 344 if (!file.is_open()) 345 throw IOException(string("Failed to open `") + filename + "'."); 346 347 // output the defines 348 const char *prefix = "_user_"; 349 size_t prefixLen = strlen(prefix); 350 for (int i = 0; i < fSyscallCount; i++) { 351 const Syscall* syscall = fSyscallVector->SyscallAt(i); 352 string name(syscall->KernelName()); 353 354 // drop the leading "_user_" prefix 355 if (name.find(prefix) != 0) 356 throw Exception(string("Bad kernel name: `") + name + "'."); 357 name = string(name, prefixLen); 358 359 // convert to upper case (is there no function for that?) 360 string defineName; 361 for (int k = 0; k < (int)name.length(); k++) 362 defineName += toupper(name[k]); 363 file << "#define SYSCALL_" << defineName << " " << i << endl; 364 } 365 } 366 367 void _WriteTableFile(const char *filename) 368 { 369 // open the syscall table output file 370 ofstream file(filename, ofstream::out | ofstream::trunc); 371 if (!file.is_open()) 372 throw IOException(string("Failed to open `") + filename + "'."); 373 374 // output syscall count 375 file << "const int kSyscallCount = " << fSyscallCount << ";" << endl; 376 file << endl; 377 378 // syscall infos array preamble 379 file << "const syscall_info kSyscallInfos[] = {" << endl; 380 381 // the syscall infos 382 for (int i = 0; i < fSyscallCount; i++) { 383 const Syscall* syscall = fSyscallVector->SyscallAt(i); 384 385 // get the parameter size 386 int paramSize = 0; 387 if (Parameter* parameter = syscall->LastParameter()) 388 paramSize = parameter->Offset() + parameter->UsedSize(); 389 390 // output the info for the syscall 391 file << "\t{ " << syscall->KernelName() << ", " 392 << paramSize << " }," << endl; 393 } 394 395 // syscall infos array end 396 file << "};" << endl; 397 } 398 399 void _WriteSTraceFile(const char *filename) 400 { 401 // open the syscall table output file 402 ofstream file(filename, ofstream::out | ofstream::trunc); 403 if (!file.is_open()) 404 throw IOException(string("Failed to open `") + filename + "'."); 405 406 // the file defines a single function get_syscalls 407 file << "void" << endl 408 << "GET_SYSCALLS(vector<Syscall*> &syscalls)" << endl 409 << "{" << endl 410 << "\tSyscall *syscall;" << endl 411 << "\tTypeHandler *handler;" << endl 412 << "(void)syscall;" << endl 413 << "(void)handler;" << endl; 414 415 int chunkSize = (fSyscallCount + 19) / 20; 416 417 // iterate through the syscalls 418 for (int i = 0; i < fSyscallCount; i++) { 419 const Syscall* syscall = fSyscallVector->SyscallAt(i); 420 421 if (i % chunkSize == 0) { 422 // chunk end 423 file << endl; 424 if (i > 0) 425 file << "#endif" << endl; 426 // chunk begin 427 file << "#ifdef SYSCALLS_CHUNK_" << (i / chunkSize) << endl; 428 } 429 430 // spacing, comment 431 file << endl; 432 file << "\t// " << syscall->Name() << endl; 433 434 // create the return type handler 435 const char* returnType = syscall->ReturnType()->TypeName(); 436 file << "\thandler = TypeHandlerFactory<" 437 << returnType 438 << ">::Create();" << endl; 439 440 // create the syscall 441 file << "\tsyscall = new Syscall(\"" << syscall->Name() << "\", " 442 << "\"" << returnType << "\", "<< "handler);" << endl; 443 file << "\tsyscalls.push_back(syscall);" << endl; 444 445 // add the parameters 446 int paramCount = syscall->CountParameters(); 447 for (int k = 0; k < paramCount; k++) { 448 const Parameter* parameter = syscall->ParameterAt(k); 449 450 // create the parameter type handler 451 file << "\thandler = TypeHandlerFactory<" 452 << parameter->TypeName() << ">::Create();" << endl; 453 454 // add the parameter 455 file << "\tsyscall->AddParameter(\"" 456 << parameter->ParameterName() << "\", " 457 << parameter->Offset() << ", \"" << parameter->TypeName() 458 << "\", handler);" << endl; 459 } 460 } 461 462 // last syscall chunk end 463 file << "#endif" << endl; 464 465 // function end 466 file << "}" << endl; 467 } 468 469 static string _GetPointerType(const char *type) 470 { 471 char *parenthesis = strchr(type, ')'); 472 if (!parenthesis) 473 return string(type) + "*"; 474 // function pointer type 475 return string(type, parenthesis - type) + "*" + parenthesis; 476 } 477 478 private: 479 SyscallVector* fSyscallVector; 480 int fSyscallCount; 481 }; 482 483 // main 484 int 485 main(int argc, char **argv) 486 { 487 try { 488 return Main().Run(argc, argv); 489 } catch (Exception &exception) { 490 fprintf(stderr, "%s\n", exception.what()); 491 return 1; 492 } 493 } 494