From efd87ab8df79399cac98d888ab3f36d3f33c34ed Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 28 Aug 2004 20:26:52 +0000 Subject: [PATCH] Had to change the mechanism for automatically generating most of the boring syscall stuff. It has two phases now: The first one (gensyscallinfos) parses syscalls.h and generates a source file containing all the required information. This file is compiled and linked to gensyscalls, which generates the actual output files. Added to the build. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8697 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tools/Jamfile | 1 + src/tools/gensyscalls/Jamfile | 109 ++++- src/tools/gensyscalls/gensyscallinfos.cpp | 521 ++++++++++++++++++++ src/tools/gensyscalls/gensyscalls.cpp | 523 +++------------------ src/tools/gensyscalls/gensyscalls.h | 21 + src/tools/gensyscalls/gensyscalls_common.h | 55 +++ 6 files changed, 784 insertions(+), 446 deletions(-) create mode 100644 src/tools/gensyscalls/gensyscallinfos.cpp create mode 100644 src/tools/gensyscalls/gensyscalls.h create mode 100644 src/tools/gensyscalls/gensyscalls_common.h diff --git a/src/tools/Jamfile b/src/tools/Jamfile index cf63182c8f..cc5f45f294 100644 --- a/src/tools/Jamfile +++ b/src/tools/Jamfile @@ -2,6 +2,7 @@ SubDir OBOS_TOP src tools ; SubInclude OBOS_TOP src tools cppunit ; SubInclude OBOS_TOP src tools elfsymbolpatcher ; +SubInclude OBOS_TOP src tools gensyscalls ; SubInclude OBOS_TOP src tools hey ; SubInclude OBOS_TOP src tools rc ; SubInclude OBOS_TOP src tools translation ; diff --git a/src/tools/gensyscalls/Jamfile b/src/tools/gensyscalls/Jamfile index 052f9f46f3..140a20fef6 100644 --- a/src/tools/gensyscalls/Jamfile +++ b/src/tools/gensyscalls/Jamfile @@ -1,4 +1,111 @@ SubDir OBOS_TOP src tools gensyscalls ; -BuildPlatformMain gensyscalls : gensyscalls.cpp ; +# build gensyscallinfos + +BuildPlatformMain gensyscallinfos : gensyscallinfos.cpp ; +LinkSharedOSLibs gensyscallinfos : stdc++.r4 ; + + +# generate the syscall infos source file + +SetupObjectsDir ; + +local syscallsHeader = [ FGristFiles syscalls.h ] ; +SEARCH on $(syscallsHeader) = [ FDirName $(OBOS_TOP) headers private kernel ] ; + +local syscallsHeaderPP = [ FGristFiles syscalls.h.pp ] ; +LOCATE on $(syscallsHeaderPP) = $(LOCATE_SOURCE) ; + +local syscallInfos = [ FGristFiles gensyscalls_infos.c ] ; +LOCATE on $(syscallInfos) = $(LOCATE_SOURCE) ; + +rule GenSyscallInfos { + Depends $(1) : gensyscallinfos $(2) ; + GenSyscallInfos1 $(1) : gensyscallinfos $(2) ; +} + +actions GenSyscallInfos1 { + $(2[1]) $(2[2]) $(1) +} + +GenSyscallInfos $(syscallInfos) : $(syscallsHeaderPP) ; + + +# build gensyscalls + +BuildPlatformMain gensyscalls : gensyscalls.cpp $(syscallInfos:S=$(SUFOBJ)) ; LinkSharedOSLibs gensyscalls : stdc++.r4 ; + + +# generate the output files + +# place them where there are needed +local syscallFiles = syscalls.S.inc syscall_dispatcher.h ; +MakeLocate syscalls.S.inc : [ FObjectsDir src kernel libroot os ] ; +MakeLocate syscall_dispatcher.h : [ FObjectsDir src kernel core ] ; +#Depends generatedFiles : $(syscallFiles) ; +#NotFile generatedFiles ; + +Depends objects/x86.R1/kernel/core : objects/x86.R1/kernel ; + +rule GenSyscallsFile { + Depends $(1) : gensyscalls ; + GenSyscallsFile1 $(1) : gensyscalls ; +} + +actions GenSyscallsFile1 { + $(2[1]) -c $(1) +} + +rule GenSyscallsDispatcher { + Depends $(1) : gensyscalls ; + GenSyscallsDispatcher1 $(1) : gensyscalls ; +} + +actions GenSyscallsDispatcher1 { + $(2[1]) -d $(1) +} + +#GenSyscalls $(syscallFiles) ; +GenSyscallsFile syscalls.S.inc ; +GenSyscallsDispatcher syscall_dispatcher.h ; + + +# preprocess the syscalls header + +SetupIncludes ; +UsePrivateHeaders kernel ; +UseArchHeaders $(OBOS_ARCH) ; + +rule Preprocess +{ + Depends $(<) : $(>) ; + + HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ; + HDRRULE on $(>) = HdrRule ; + HDRSCAN on $(>) = $(HDRPATTERN) ; + HDRSEARCH on $(>) = + $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ; + + HDRGRIST on $(>) = $(HDRGRIST) ; + + DEFINES on $(<) += $(DEFINES) ; + + CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) $(OPTIM) + [ FDefines GEN_SYSCALL_INFOS_PROCESSING ] ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +actions Preprocess +{ + $(CC) -E "$(2)" $(CCFLAGS) $(CCDEFS) $(CCHDRS) -o "$(1)" ; +} + +Preprocess $(syscallsHeaderPP) : $(syscallsHeader) ; + + +# compile the syscall infos source file + +Object $(syscallInfos:S=$(SUFOBJ)) : $(syscallInfos) ; diff --git a/src/tools/gensyscalls/gensyscallinfos.cpp b/src/tools/gensyscalls/gensyscallinfos.cpp new file mode 100644 index 0000000000..20c1cbb241 --- /dev/null +++ b/src/tools/gensyscalls/gensyscallinfos.cpp @@ -0,0 +1,521 @@ +// gensyscallinfos.cpp +// +// Copyright (c) 2004, Ingo Weinhold +// All rights reserved. Distributed under the terms of the OpenBeOS License. + +#include +#include +#include +#include +#include +#include +#include + +#include "gensyscalls_common.h" + +// usage +const char *kUsage = +"Usage: gensyscallinfos
\n" +"\n" +"Given the (preprocessed) header file that defines the syscall prototypes the\n" +"command generates a source file consisting of syscall infos, which is needed\n" +"to build gensyscalls, which in turn generates the assembly syscall\n" +"definitions and code for the kernelland syscall dispatcher.\n" +"\n" +"
- Input: The preprocessed header file with the\n" +" syscall prototypes.\n" +" - Output: The syscall infos source file needed to\n" +" build gensyscalls."; + +// print_usage +static +void +print_usage(bool error) +{ + fprintf((error ? stderr : stdout), kUsage); +} + +// Type +struct Type { + Type(const char *type) : type(type) {} + Type(const string &type) : type(type) {} + + string type; +}; + +// Function +class Function { +public: + Function() : fReturnType("") {} + + void SetName(const string &name) + { + fName = name; + } + + const string &GetName() const + { + return fName; + } + + void AddParameter(const Type &type) + { + fParameters.push_back(type); + } + + int CountParameters() const + { + return fParameters.size(); + } + + const Type &ParameterAt(int index) const + { + return fParameters[index]; + } + + void SetReturnType(const Type &type) + { + fReturnType = type; + } + + const Type &GetReturnType() const + { + return fReturnType; + } + +protected: + string fName; + vector fParameters; + Type fReturnType; +}; + +// Syscall +class Syscall : public Function { +public: + string GetKernelName() const + { + int baseIndex = 0; + if (fName.find("_kern_") == 0) + baseIndex = strlen("_kern_"); + else if (fName.find("sys_") == 0) + baseIndex = strlen("sys_"); + string kernelName("_user_"); + kernelName.append(string(fName, baseIndex)); + return kernelName; + } +}; + +// Tokenizer +class Tokenizer { +public: + Tokenizer(istream &input) + : fInput(input), + fHasCurrent(false) + { + } + + string GetCurrentToken() + { + if (!fHasCurrent) + throw Exception("GetCurrentToken(): No current token!"); + return fTokens.front(); + } + + string GetNextToken() + { + return GetNextToken(NULL); + } + + string GetNextToken(stack &skippedTokens) + { + return GetNextToken(&skippedTokens); + } + + string GetNextToken(stack *skippedTokens) + { + if (fHasCurrent) { + fTokens.pop_front(); + fHasCurrent = false; + } + while (fTokens.empty()) + _ReadLine(); + fHasCurrent = true; + if (skippedTokens) + skippedTokens->push(fTokens.front()); + return fTokens.front(); + } + + void ExpectToken(const string &expectedToken) + { + string token = GetCurrentToken(); + if (expectedToken != token) { + throw ParseException(string("Unexpected token `") + token + + "'. Expected was `" + expectedToken + "'."); + } + } + + void ExpectNextToken(const string &expectedToken) + { + GetNextToken(); + ExpectToken(expectedToken); + } + + bool CheckToken(const string &expectedToken) + { + string token = GetCurrentToken(); + return (expectedToken == token); + } + + bool CheckNextToken(const string &expectedToken) + { + GetNextToken(); + bool result = CheckToken(expectedToken); + if (!result) + PutCurrentToken(); + return result; + } + + void PutCurrentToken() + { + if (!fHasCurrent) + throw Exception("GetCurrentToken(): No current token!"); + fHasCurrent = false; + } + + void PutToken(string token) + { + if (fHasCurrent) { + fTokens.pop_front(); + fHasCurrent = false; + } + fTokens.push_front(token); + } + + void PutTokens(stack &tokens) + { + if (fHasCurrent) { + fTokens.pop_front(); + fHasCurrent = false; + } + while (!tokens.empty()) { + fTokens.push_front(tokens.top()); + tokens.pop(); + } + } + +private: + void _ReadLine() + { + // read the line + char buffer[10240]; + if (!fInput.getline(buffer, sizeof(buffer))) + throw EOFException("Unexpected end of input."); + // parse it + int len = strlen(buffer); + int tokenStart = 0; + for (int i = 0; i < len; i++) { + char c = buffer[i]; + if (isspace(c)) { + if (tokenStart < i) + fTokens.push_back(string(buffer + tokenStart, buffer + i)); + tokenStart = i + 1; + continue; + } + switch (buffer[i]) { + case '#': + case '(': + case ')': + case '*': + case '&': + case '[': + case ']': + case ';': + case ',': + if (tokenStart < i) { + fTokens.push_back(string(buffer + tokenStart, + buffer + i)); + } + fTokens.push_back(string(buffer + i, buffer + i + 1)); + tokenStart = i + 1; + break; + } + } + if (tokenStart < len) + fTokens.push_back(string(buffer + tokenStart, buffer + len)); + } + +private: + istream &fInput; + list fTokens; + bool fHasCurrent; +}; + + +// Main +class Main { +public: + + int Run(int argc, char **argv) + { + // parse parameters + if (argc >= 2 + && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) { + print_usage(false); + return 0; + } + if (argc != 3) { + print_usage(true); + return 1; + } + _ParseSyscalls(argv[1]); + _WriteSyscallInfoFile(argv[2]); + return 0; + } + + +private: + void _ParseSyscalls(const char *filename) + { + // open the input file + ifstream file(filename, ifstream::in); + if (!file.is_open()) + throw new IOException(string("Failed to open `") + filename + "'."); + // parse the syscalls + Tokenizer tokenizer(file); + // find "#pragma syscalls begin" + while (true) { + while (tokenizer.GetNextToken() != "#"); + stack skippedTokens; + if (tokenizer.GetNextToken(skippedTokens) == "pragma" + && tokenizer.GetNextToken(skippedTokens) == "syscalls" + && tokenizer.GetNextToken(skippedTokens) == "begin") { + break; + } + tokenizer.PutTokens(skippedTokens); + } + // parse the functions + while (!tokenizer.CheckNextToken("#")) { + Syscall syscall; + _ParseSyscall(tokenizer, syscall); + fSyscalls.push_back(syscall); + } + // expect "pragma syscalls end" + tokenizer.ExpectNextToken("pragma"); + tokenizer.ExpectNextToken("syscalls"); + tokenizer.ExpectNextToken("end"); + +// for (int i = 0; i < (int)fSyscalls.size(); i++) { +// const Syscall &syscall = fSyscalls[i]; +// printf("syscall: `%s'\n", syscall.GetName().c_str()); +// for (int k = 0; k < (int)syscall.CountParameters(); k++) +// printf(" arg: `%s'\n", syscall.ParameterAt(k).type.c_str()); +// printf(" return type: `%s'\n", +// syscall.GetReturnType().type.c_str()); +// } +// printf("Found %lu syscalls.\n", fSyscalls.size()); + } + + void _WriteSyscallInfoFile(const char *filename) + { + // open the syscall info file + ofstream file(filename, ofstream::out | ofstream::trunc); + if (!file.is_open()) + throw new IOException(string("Failed to open `") + filename + "'."); + // write preamble + file << "#include \"gensyscalls.h\"" << endl; + file << "#include \"syscalls.h\"" << endl; + file << endl; + // output the case statements + for (int i = 0; i < (int)fSyscalls.size(); i++) { + const Syscall &syscall = fSyscalls[i]; + string name = string("gensyscall_") + syscall.GetName(); + string paramInfoName = name + "_parameter_info"; + int paramCount = syscall.CountParameters(); + // write the parameter infos + file << "static gensyscall_parameter_info " << paramInfoName + << "[] = {" << endl; + for (int k = 0; k < paramCount; k++) { + file << "\t{ \"" << syscall.ParameterAt(k).type << "\", 0, " + << "sizeof(" << syscall.ParameterAt(k).type << "), 0 }," + << endl; + } + file << "};" << endl; + file << endl; + // write the initialization function + file << "static void " << name << "("; + for (int k = 0; k < paramCount; k++) { + if (k > 0) + file << ", "; + string type = syscall.ParameterAt(k).type; + string::size_type pos = type.find(")"); + if (pos == string::npos) { + file << type << " arg" << k; + } else { + // function pointer + file << string(type, 0, pos) << " arg" << k + << string(type, pos, type.length() - pos); + } + } + if (paramCount > 0) + file << ", "; + file << "int arg" << paramCount << ") {" << endl; + for (int k = 0; k < paramCount; k++) { + file << "\t" << paramInfoName << "[" << k << "].offset = " + << "(char*)&arg" << k << " - (char*)&arg0;" << endl; + file << "\t" << paramInfoName << "[" << k << "].actual_size = " + << "(char*)&arg" << (k + 1) << " - (char*)&arg" << k << ";" + << endl; + } + file << "}" << endl; + file << endl; + } + // write the syscall infos + file << "static gensyscall_syscall_info " + "gensyscall_syscall_infos[] = {" << endl; + for (int i = 0; i < (int)fSyscalls.size(); i++) { + const Syscall &syscall = fSyscalls[i]; + string name = string("gensyscall_") + syscall.GetName(); + string paramInfoName = name + "_parameter_info"; + file << "\t{ \"" << syscall.GetName() << "\", " + << "\"" << syscall.GetKernelName() << "\", " + << "\"" << syscall.GetReturnType().type << "\", " + << syscall.CountParameters() << ", " + << paramInfoName << " }," << endl; + } + file << "};" << endl; + file << endl; + // write the initialization function + file << "gensyscall_syscall_info *gensyscall_get_infos(int *count);"; + file << "gensyscall_syscall_info *gensyscall_get_infos(int *count) {" + << endl; + for (int i = 0; i < (int)fSyscalls.size(); i++) { + const Syscall &syscall = fSyscalls[i]; + string name = string("gensyscall_") + syscall.GetName(); + file << "\t" << name << "("; + int paramCount = syscall.CountParameters(); + // write the dummy parameters + for (int k = 0; k < paramCount; k++) + file << "(" << syscall.ParameterAt(k).type << ")0, "; + file << "0);" << endl; + } + file << "\t*count = " << fSyscalls.size() << ";" << endl; + file << "\treturn gensyscall_syscall_infos;" << endl; + file << "}" << endl; + } + + void _ParseSyscall(Tokenizer &tokenizer, Syscall &syscall) + { + // get return type and function name + vector returnType; + while (tokenizer.GetNextToken() != "(") { + string token = tokenizer.GetCurrentToken(); + // strip leading "extern" + if (!returnType.empty() || token != "extern") + returnType.push_back(token); + } + if (returnType.size() < 2) { + throw ParseException("Error while parsing function " + "return type."); + } + syscall.SetName(returnType[returnType.size() - 1]); + returnType.pop_back(); + string returnTypeString(returnType[0]); + for (int i = 1; i < (int)returnType.size(); i++) { + returnTypeString += " "; + returnTypeString += returnType[i]; + } + syscall.SetReturnType(returnTypeString); + // get arguments + if (!tokenizer.CheckNextToken(")")) { + _ParseParameter(tokenizer, syscall); + while (!tokenizer.CheckNextToken(")")) { + tokenizer.ExpectNextToken(","); + _ParseParameter(tokenizer, syscall); + } + } + tokenizer.ExpectNextToken(";"); + } + + void _ParseParameter(Tokenizer &tokenizer, Syscall &syscall) + { + vector type; + while (tokenizer.GetNextToken() != ")" + && tokenizer.GetCurrentToken() != ",") { + string token = tokenizer.GetCurrentToken(); + type.push_back(token); + if (token == "(") { + // This must be a function pointer. We deal with that in a + // separate method. + _ParseFunctionPointerParameter(tokenizer, syscall, type); + return; + } + } + tokenizer.PutCurrentToken(); + if (type.size() < 2) { + if (type.size() == 1 && type[0] == "void") { + // that's OK + return; + } + throw ParseException("Error while parsing function " + "parameter."); + } + type.pop_back(); // last component is the parameter name + string typeString(type[0]); + for (int i = 1; i < (int)type.size(); i++) { + typeString += " "; + typeString += type[i]; + } + syscall.AddParameter(typeString); + } + + void _ParseFunctionPointerParameter(Tokenizer &tokenizer, Syscall &syscall, + vector &type) + { + // When this method is entered, the return type and the opening + // parenthesis must already be parse and stored in the supplied type + // vector. + if (type.size() < 2) { + throw ParseException("Error parsing function parameter. " + "No return type."); + } + // read all the "*"s there are + while (tokenizer.CheckNextToken("*")) + type.push_back("*"); + // now comes the parameter name, if specified -- skip it + if (!tokenizer.CheckNextToken(")")) { + tokenizer.GetNextToken(); + tokenizer.ExpectNextToken(")"); + } + type.push_back(")"); + // the function parameters + tokenizer.ExpectNextToken("("); + type.push_back("("); + while (!tokenizer.CheckNextToken(")")) + type.push_back(tokenizer.GetNextToken()); + type.push_back(")"); + // compose the type string and add it to the syscall parameters + string typeString(type[0]); + for (int i = 1; i < (int)type.size(); i++) { + typeString += " "; + typeString += type[i]; + } + syscall.AddParameter(typeString); + } + +private: + vector fSyscalls; +}; + + +// main +int +main(int argc, char **argv) +{ + try { + return Main().Run(argc, argv); + } catch (Exception &exception) { + fprintf(stderr, "%s\n", exception.what()); + return 1; + } +} + diff --git a/src/tools/gensyscalls/gensyscalls.cpp b/src/tools/gensyscalls/gensyscalls.cpp index ea9dbfcc99..3b64916f1a 100644 --- a/src/tools/gensyscalls/gensyscalls.cpp +++ b/src/tools/gensyscalls/gensyscalls.cpp @@ -1,29 +1,24 @@ // gensyscalls.cpp -// -// Copyright (c) 2004, Ingo Weinhold -// All rights reserved. Distributed under the terms of the OpenBeOS License. -#include +#include +#include #include -#include -#include -#include -#include #include -#include + +#include "gensyscalls.h" +#include "gensyscalls_common.h" + +extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count); // usage const char *kUsage = -"Usage: gensyscalls
\n" +"Usage: gensyscalls [ -c ] [ -d ]\n" "\n" -"Given the (preprocessed) header file that defines the syscall prototypes the\n" -"command generates a piece of assembly source file that defines the actual\n" -"syscalls and a piece of C source (cases of a switch statement) for the \n" -"kernel syscall dispatcher. Either file is to be included from a respective\n" -"skeleton source file.\n" +"The command generates a piece of assembly source file that defines the\n" +"actual syscalls and a piece of C source (cases of a switch statement) for" +"the kernel syscall dispatcher. Either file is to be included from a" +"respective skeleton source file.\n" "\n" -"
- Input: The preprocessed header file with the\n" -" syscall prototypes.\n" " - Output: The assembly source file implementing the\n" " actual syscalls." " - Output: The C source file to be included by the\n" @@ -37,343 +32,68 @@ print_usage(bool error) fprintf((error ? stderr : stdout), kUsage); } -// Type -struct Type { - Type(const char *type) : type(type) {} - Type(const string &type) : type(type) {} - - string type; -}; - -// Function -class Function { -public: - Function() : fReturnType("") {} - - void SetName(const string &name) - { - fName = name; - } - - const string &GetName() const - { - return fName; - } - - void AddParameter(const Type &type) - { - fParameters.push_back(type); - } - - int CountParameters() const - { - return fParameters.size(); - } - - const Type &ParameterAt(int index) const - { - return fParameters[index]; - } - - void SetReturnType(const Type &type) - { - fReturnType = type; - } - - const Type &GetReturnType() const - { - return fReturnType; - } - -protected: - string fName; - vector fParameters; - Type fReturnType; -}; - -// Syscall -class Syscall : public Function { -public: - string GetKernelName() const - { - int baseIndex = 0; - if (fName.find("_kern_") == 0) - baseIndex = strlen("_kern_"); - else if (fName.find("sys_") == 0) - baseIndex = strlen("sys_"); - string kernelName("_user_"); - kernelName.append(string(fName, baseIndex)); - return kernelName; - } -}; - -// Exception -struct Exception : exception { - Exception() - : fMessage() - { - } - - Exception(const string &message) - : fMessage(message) - { - } - - virtual ~Exception() {} - - virtual const char *what() const - { - return fMessage.c_str(); - } - -private: - string fMessage; -}; - -// EOFException -struct EOFException : public Exception { - EOFException() {} - EOFException(const string &message) : Exception(message) {} - virtual ~EOFException() {} -}; - -// IOException -struct IOException : public Exception { - IOException() {} - IOException(const string &message) : Exception(message) {} - virtual ~IOException() {} -}; - -// ParseException -struct ParseException : public Exception { - ParseException() {} - ParseException(const string &message) : Exception(message) {} - virtual ~ParseException() {} -}; - - -// Tokenizer -class Tokenizer { -public: - Tokenizer(istream &input) - : fInput(input), - fHasCurrent(false) - { - } - - string GetCurrentToken() - { - if (!fHasCurrent) - throw Exception("GetCurrentToken(): No current token!"); - return fTokens.front(); - } - - string GetNextToken() - { - return GetNextToken(NULL); - } - - string GetNextToken(stack &skippedTokens) - { - return GetNextToken(&skippedTokens); - } - - string GetNextToken(stack *skippedTokens) - { - if (fHasCurrent) { - fTokens.pop_front(); - fHasCurrent = false; - } - while (fTokens.empty()) - _ReadLine(); - fHasCurrent = true; - if (skippedTokens) - skippedTokens->push(fTokens.front()); - return fTokens.front(); - } - - void ExpectToken(const string &expectedToken) - { - string token = GetCurrentToken(); - if (expectedToken != token) { - throw ParseException(string("Unexpected token `") + token - + "'. Expected was `" + expectedToken + "'."); - } - } - - void ExpectNextToken(const string &expectedToken) - { - GetNextToken(); - ExpectToken(expectedToken); - } - - bool CheckToken(const string &expectedToken) - { - string token = GetCurrentToken(); - return (expectedToken == token); - } - - bool CheckNextToken(const string &expectedToken) - { - GetNextToken(); - bool result = CheckToken(expectedToken); - if (!result) - PutCurrentToken(); - return result; - } - - void PutCurrentToken() - { - if (!fHasCurrent) - throw Exception("GetCurrentToken(): No current token!"); - fHasCurrent = false; - } - - void PutToken(string token) - { - if (fHasCurrent) { - fTokens.pop_front(); - fHasCurrent = false; - } - fTokens.push_front(token); - } - - void PutTokens(stack &tokens) - { - if (fHasCurrent) { - fTokens.pop_front(); - fHasCurrent = false; - } - while (!tokens.empty()) { - fTokens.push_front(tokens.top()); - tokens.pop(); - } - } - -private: - void _ReadLine() - { - // read the line - char buffer[10240]; - if (!fInput.getline(buffer, sizeof(buffer))) - throw EOFException("Unexpected end of input."); - // parse it - int len = strlen(buffer); - int tokenStart = 0; - for (int i = 0; i < len; i++) { - char c = buffer[i]; - if (isspace(c)) { - if (tokenStart < i) - fTokens.push_back(string(buffer + tokenStart, buffer + i)); - tokenStart = i + 1; - continue; - } - switch (buffer[i]) { - case '#': - case '(': - case ')': - case '*': - case '&': - case '[': - case ']': - case ';': - case ',': - if (tokenStart < i) { - fTokens.push_back(string(buffer + tokenStart, - buffer + i)); - } - fTokens.push_back(string(buffer + i, buffer + i + 1)); - tokenStart = i + 1; - break; - } - } - if (tokenStart < len) - fTokens.push_back(string(buffer + tokenStart, buffer + len)); - } - -private: - istream &fInput; - list fTokens; - bool fHasCurrent; -}; - - // Main class Main { public: int Run(int argc, char **argv) { - // parse parameters - if (argc >= 2 - && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) { - print_usage(false); + // parse arguments + const char *syscallsFile = NULL; + const char *dispatcherFile = NULL; + for (int argi = 1; argi < argc; argi++) { + string arg(argv[argi]); + if (arg == "-h" || arg == "--help") { + print_usage(false); + return 0; + } else if (arg == "-c") { + if (argi + 1 >= argc) { + print_usage(true); + return 1; + } + syscallsFile = argv[++argi]; + } else if (arg == "-d") { + if (argi + 1 >= argc) { + print_usage(true); + return 1; + } + dispatcherFile = argv[++argi]; + } else { + print_usage(true); + return 1; + } + } + fSyscallInfos = gensyscall_get_infos(&fSyscallCount); + if (!syscallsFile && !dispatcherFile) { + printf("Found %d syscalls.\n", fSyscallCount); return 0; } - if (argc != 4) { - print_usage(true); - return 1; - } - _ParseSyscalls(argv[1]); - _WriteSyscallsFile(argv[2]); - _WriteDispatcherFile(argv[3]); + // generate the output + if (syscallsFile) + _WriteSyscallsFile(syscallsFile); + if (dispatcherFile) + _WriteDispatcherFile(dispatcherFile); return 0; } - -private: - void _ParseSyscalls(const char *filename) - { - // open the input file - ifstream file(filename, ifstream::in); - if (!file.is_open()) - throw new IOException(string("Failed to open `") + filename + "'."); - // parse the syscalls - Tokenizer tokenizer(file); - // find "#pragma syscalls begin" - while (true) { - while (tokenizer.GetNextToken() != "#"); - stack skippedTokens; - if (tokenizer.GetNextToken(skippedTokens) == "pragma" - && tokenizer.GetNextToken(skippedTokens) == "syscalls" - && tokenizer.GetNextToken(skippedTokens) == "begin") { - break; - } - tokenizer.PutTokens(skippedTokens); - } - // parse the functions - while (!tokenizer.CheckNextToken("#")) { - Syscall syscall; - _ParseSyscall(tokenizer, syscall); - fSyscalls.push_back(syscall); - } - // expect "pragma syscalls end" - tokenizer.ExpectNextToken("pragma"); - tokenizer.ExpectNextToken("syscalls"); - tokenizer.ExpectNextToken("end"); - -// for (int i = 0; i < (int)fSyscalls.size(); i++) { -// const Syscall &syscall = fSyscalls[i]; -// printf("syscall: `%s'\n", syscall.GetName().c_str()); -// for (int k = 0; k < (int)syscall.CountParameters(); k++) -// printf(" arg: `%s'\n", syscall.ParameterAt(k).type.c_str()); -// printf(" return type: `%s'\n", -// syscall.GetReturnType().type.c_str()); -// } -// printf("Found %lu syscalls.\n", fSyscalls.size()); - } - void _WriteSyscallsFile(const char *filename) { // open the syscalls output file ofstream file(filename, ofstream::out | ofstream::trunc); if (!file.is_open()) - throw new IOException(string("Failed to open `") + filename + "'."); + throw IOException(string("Failed to open `") + filename + "'."); // output the syscalls definitions - for (int i = 0; i < (int)fSyscalls.size(); i++) { - const Syscall &syscall = fSyscalls[i]; - file << "SYSCALL" << syscall.CountParameters() << "(" - << syscall.GetName() << ", " << i << ")" << endl; + for (int i = 0; i < fSyscallCount; i++) { + const gensyscall_syscall_info &syscall = fSyscallInfos[i]; + int paramCount = syscall.parameter_count; + int paramSize = 0; + gensyscall_parameter_info* parameters = syscall.parameters; + for (int k = 0; k < paramCount; k++) { + int size = parameters[k].actual_size; + paramSize += (size + 3) / 4 * 4; + } + file << "SYSCALL" << (paramSize / 4) << "(" + << syscall.name << ", " << i << ")" << endl; } } @@ -382,129 +102,43 @@ private: // open the dispatcher output file ofstream file(filename, ofstream::out | ofstream::trunc); if (!file.is_open()) - throw new IOException(string("Failed to open `") + filename + "'."); + throw IOException(string("Failed to open `") + filename + "'."); // output the case statements - for (int i = 0; i < (int)fSyscalls.size(); i++) { - const Syscall &syscall = fSyscalls[i]; + for (int i = 0; i < fSyscallCount; i++) { + const gensyscall_syscall_info &syscall = fSyscallInfos[i]; file << "case " << i << ":" << endl; file << "\t"; - if (syscall.GetReturnType().type != "void") + if (string(syscall.return_type) != "void") file << "*call_ret = "; - file << syscall.GetKernelName() << "("; - if (syscall.CountParameters() > 0) { - file << "(" << syscall.ParameterAt(0).type << ")arg0"; - for (int k = 1; k < (int)syscall.CountParameters(); k++) - file << ", (" << syscall.ParameterAt(k).type << ")arg" << k; + file << syscall.kernel_name << "("; + int paramCount = syscall.parameter_count; + if (paramCount > 0) { + gensyscall_parameter_info* parameters = syscall.parameters; + file << "*(" << _GetPointerType(parameters[0].type) << ")args"; + for (int k = 1; k < paramCount; k++) { + file << ", *(" << _GetPointerType(parameters[k].type) + << ")((char*)args + " << parameters[k].offset << ")"; + } } file << ");" << endl; file << "\tbreak;" << endl; } } - void _ParseSyscall(Tokenizer &tokenizer, Syscall &syscall) + static string _GetPointerType(const char *type) { - // get return type and function name - vector returnType; - while (tokenizer.GetNextToken() != "(") { - string token = tokenizer.GetCurrentToken(); - // strip leading "extern" - if (!returnType.empty() || token != "extern") - returnType.push_back(token); - } - if (returnType.size() < 2) { - throw ParseException("Error while parsing function " - "return type."); - } - syscall.SetName(returnType[returnType.size() - 1]); - returnType.pop_back(); - string returnTypeString(returnType[0]); - for (int i = 1; i < (int)returnType.size(); i++) { - returnTypeString += " "; - returnTypeString += returnType[i]; - } - syscall.SetReturnType(returnTypeString); - // get arguments - if (!tokenizer.CheckNextToken(")")) { - _ParseParameter(tokenizer, syscall); - while (!tokenizer.CheckNextToken(")")) { - tokenizer.ExpectNextToken(","); - _ParseParameter(tokenizer, syscall); - } - } - tokenizer.ExpectNextToken(";"); - } - - void _ParseParameter(Tokenizer &tokenizer, Syscall &syscall) - { - vector type; - while (tokenizer.GetNextToken() != ")" - && tokenizer.GetCurrentToken() != ",") { - string token = tokenizer.GetCurrentToken(); - type.push_back(token); - if (token == "(") { - // This must be a function pointer. We deal with that in a - // separate method. - _ParseFunctionPointerParameter(tokenizer, syscall, type); - return; - } - } - tokenizer.PutCurrentToken(); - if (type.size() < 2) { - if (type.size() == 1 && type[0] == "void") { - // that's OK - return; - } - throw ParseException("Error while parsing function " - "parameter."); - } - type.pop_back(); // last component is the parameter name - string typeString(type[0]); - for (int i = 1; i < (int)type.size(); i++) { - typeString += " "; - typeString += type[i]; - } - syscall.AddParameter(typeString); - } - - void _ParseFunctionPointerParameter(Tokenizer &tokenizer, Syscall &syscall, - vector &type) - { - // When this method is entered, the return type and the opening - // parenthesis must already be parse and stored in the supplied type - // vector. - if (type.size() < 2) { - throw ParseException("Error parsing function parameter. " - "No return type."); - } - // read all the "*"s there are - while (tokenizer.CheckNextToken("*")) - type.push_back("*"); - // now comes the parameter name, if specified -- skip it - if (!tokenizer.CheckNextToken(")")) { - tokenizer.GetNextToken(); - tokenizer.ExpectNextToken(")"); - } - type.push_back(")"); - // the function parameters - tokenizer.ExpectNextToken("("); - type.push_back("("); - while (!tokenizer.CheckNextToken(")")) - type.push_back(tokenizer.GetNextToken()); - type.push_back(")"); - // compose the type string and add it to the syscall parameters - string typeString(type[0]); - for (int i = 1; i < (int)type.size(); i++) { - typeString += " "; - typeString += type[i]; - } - syscall.AddParameter(typeString); + char *parenthesis = strchr(type, ')'); + if (!parenthesis) + return string(type) + "*"; + // function pointer type + return string(type, parenthesis - type) + "*" + parenthesis; } private: - vector fSyscalls; + const gensyscall_syscall_info *fSyscallInfos; + int fSyscallCount; }; - // main int main(int argc, char **argv) @@ -516,4 +150,3 @@ main(int argc, char **argv) return 1; } } - diff --git a/src/tools/gensyscalls/gensyscalls.h b/src/tools/gensyscalls/gensyscalls.h new file mode 100644 index 0000000000..995187e5a9 --- /dev/null +++ b/src/tools/gensyscalls/gensyscalls.h @@ -0,0 +1,21 @@ +// gensyscalls.h + +#ifndef _GEN_SYSCALLS_H +#define _GEN_SYSCALLS_H + +typedef struct gensyscall_parameter_info { + const char *type; + int offset; + int size; + int actual_size; +} gensyscall_parameter_info; + +typedef struct gensyscall_syscall_info { + const char *name; + const char *kernel_name; + const char *return_type; + int parameter_count; + gensyscall_parameter_info *parameters; +} gensyscall_syscall_info; + +#endif // _GEN_SYSCALLS_H diff --git a/src/tools/gensyscalls/gensyscalls_common.h b/src/tools/gensyscalls/gensyscalls_common.h new file mode 100644 index 0000000000..8dc26b522f --- /dev/null +++ b/src/tools/gensyscalls/gensyscalls_common.h @@ -0,0 +1,55 @@ +// gensyscalls_common.h + +#ifndef _GEN_SYSCALLS_COMMON_H +#define _GEN_SYSCALLS_COMMON_H + +#include + +// Exception +struct Exception : exception { + Exception() + : fMessage() + { + } + + Exception(const string &message) + : fMessage(message) + { + } + + virtual ~Exception() {} + + virtual const char *what() const + { + return fMessage.c_str(); + } + +private: + string fMessage; +}; + +// EOFException +struct EOFException : public Exception { + EOFException() {} + EOFException(const string &message) : Exception(message) {} + virtual ~EOFException() {} +}; + +// IOException +struct IOException : public Exception { + IOException() {} + IOException(const string &message) : Exception(message) {} + virtual ~IOException() {} +}; + +// ParseException +struct ParseException : public Exception { + ParseException() {} + ParseException(const string &message) : Exception(message) {} + virtual ~ParseException() {} +}; + + + + +#endif // _GEN_SYSCALLS_COMMON_H