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
This commit is contained in:
Ingo Weinhold 2004-08-28 20:26:52 +00:00
parent cc868bc230
commit efd87ab8df
6 changed files with 784 additions and 446 deletions

View File

@ -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 ;

View File

@ -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>syscalls.S.inc <syscalls>syscall_dispatcher.h ;
MakeLocate <syscalls>syscalls.S.inc : [ FObjectsDir src kernel libroot os ] ;
MakeLocate <syscalls>syscall_dispatcher.h : [ FObjectsDir src kernel core ] ;
#Depends <syscalls>generatedFiles : $(syscallFiles) ;
#NotFile <syscalls>generatedFiles ;
Depends <dir>objects/x86.R1/kernel/core : <dir>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>syscalls.S.inc ;
GenSyscallsDispatcher <syscalls>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) ;

View File

@ -0,0 +1,521 @@
// gensyscallinfos.cpp
//
// Copyright (c) 2004, Ingo Weinhold <bonefish@cs.tu-berlin.de>
// All rights reserved. Distributed under the terms of the OpenBeOS License.
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <list>
#include <stack>
#include <string>
#include <vector>
#include "gensyscalls_common.h"
// usage
const char *kUsage =
"Usage: gensyscallinfos <header> <calls> <dispatcher>\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"
" <header> - Input: The preprocessed header file with the\n"
" syscall prototypes.\n"
" <syscall infos> - 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<Type> 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<string> &skippedTokens)
{
return GetNextToken(&skippedTokens);
}
string GetNextToken(stack<string> *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<string> &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<string> 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<string> 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<string> 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<string> 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<string> &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<Syscall> 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;
}
}

View File

@ -1,29 +1,24 @@
// gensyscalls.cpp
//
// Copyright (c) 2004, Ingo Weinhold <bonefish@cs.tu-berlin.de>
// All rights reserved. Distributed under the terms of the OpenBeOS License.
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <list>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include "gensyscalls.h"
#include "gensyscalls_common.h"
extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count);
// usage
const char *kUsage =
"Usage: gensyscalls <header> <calls> <dispatcher>\n"
"Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ]\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"
" <header> - Input: The preprocessed header file with the\n"
" syscall prototypes.\n"
" <calls> - Output: The assembly source file implementing the\n"
" actual syscalls."
" <dispatcher> - Output: The C source file to be included by the\n"
@ -37,330 +32,48 @@ 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<Type> 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<string> &skippedTokens)
{
return GetNextToken(&skippedTokens);
}
string GetNextToken(stack<string> *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<string> &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<string> 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")) {
// 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;
}
if (argc != 4) {
} else if (arg == "-c") {
if (argi + 1 >= argc) {
print_usage(true);
return 1;
}
_ParseSyscalls(argv[1]);
_WriteSyscallsFile(argv[2]);
_WriteDispatcherFile(argv[3]);
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;
}
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<string> 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());
// generate the output
if (syscallsFile)
_WriteSyscallsFile(syscallsFile);
if (dispatcherFile)
_WriteDispatcherFile(dispatcherFile);
return 0;
}
void _WriteSyscallsFile(const char *filename)
@ -368,12 +81,19 @@ private:
// 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<string> 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<string> 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<string> &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<Syscall> 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;
}
}

View File

@ -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

View File

@ -0,0 +1,55 @@
// gensyscalls_common.h
#ifndef _GEN_SYSCALLS_COMMON_H
#define _GEN_SYSCALLS_COMMON_H
#include <string>
// 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