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