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:
@@ -2,6 +2,7 @@ SubDir OBOS_TOP src tools ;
|
|||||||
|
|
||||||
SubInclude OBOS_TOP src tools cppunit ;
|
SubInclude OBOS_TOP src tools cppunit ;
|
||||||
SubInclude OBOS_TOP src tools elfsymbolpatcher ;
|
SubInclude OBOS_TOP src tools elfsymbolpatcher ;
|
||||||
|
SubInclude OBOS_TOP src tools gensyscalls ;
|
||||||
SubInclude OBOS_TOP src tools hey ;
|
SubInclude OBOS_TOP src tools hey ;
|
||||||
SubInclude OBOS_TOP src tools rc ;
|
SubInclude OBOS_TOP src tools rc ;
|
||||||
SubInclude OBOS_TOP src tools translation ;
|
SubInclude OBOS_TOP src tools translation ;
|
||||||
|
|||||||
@@ -1,4 +1,111 @@
|
|||||||
SubDir OBOS_TOP src tools gensyscalls ;
|
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 ;
|
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) ;
|
||||||
|
|||||||
@@ -0,0 +1,521 @@
|
|||||||
|
// gensyscallinfos.cpp
|
||||||
|
//
|
||||||
|
// Copyright (c) 2004, Ingo Weinhold <[email protected]>
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,29 +1,24 @@
|
|||||||
// gensyscalls.cpp
|
// gensyscalls.cpp
|
||||||
//
|
|
||||||
// Copyright (c) 2004, Ingo Weinhold <[email protected]>
|
|
||||||
// All rights reserved. Distributed under the terms of the OpenBeOS License.
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <list>
|
|
||||||
#include <stack>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
#include "gensyscalls.h"
|
||||||
|
#include "gensyscalls_common.h"
|
||||||
|
|
||||||
|
extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count);
|
||||||
|
|
||||||
// usage
|
// usage
|
||||||
const char *kUsage =
|
const char *kUsage =
|
||||||
"Usage: gensyscalls <header> <calls> <dispatcher>\n"
|
"Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Given the (preprocessed) header file that defines the syscall prototypes the\n"
|
"The command generates a piece of assembly source file that defines the\n"
|
||||||
"command generates a piece of assembly source file that defines the actual\n"
|
"actual syscalls and a piece of C source (cases of a switch statement) for"
|
||||||
"syscalls and a piece of C source (cases of a switch statement) for the \n"
|
"the kernel syscall dispatcher. Either file is to be included from a"
|
||||||
"kernel syscall dispatcher. Either file is to be included from a respective\n"
|
"respective skeleton source file.\n"
|
||||||
"skeleton source file.\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" <header> - Input: The preprocessed header file with the\n"
|
|
||||||
" syscall prototypes.\n"
|
|
||||||
" <calls> - Output: The assembly source file implementing the\n"
|
" <calls> - Output: The assembly source file implementing the\n"
|
||||||
" actual syscalls."
|
" actual syscalls."
|
||||||
" <dispatcher> - Output: The C source file to be included by the\n"
|
" <dispatcher> - Output: The C source file to be included by the\n"
|
||||||
@@ -37,343 +32,68 @@ print_usage(bool error)
|
|||||||
fprintf((error ? stderr : stdout), kUsage);
|
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
|
// Main
|
||||||
class Main {
|
class Main {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int Run(int argc, char **argv)
|
int Run(int argc, char **argv)
|
||||||
{
|
{
|
||||||
// parse parameters
|
// parse arguments
|
||||||
if (argc >= 2
|
const char *syscallsFile = NULL;
|
||||||
&& (string(argv[1]) == "-h" || string(argv[1]) == "--help")) {
|
const char *dispatcherFile = NULL;
|
||||||
print_usage(false);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
if (argc != 4) {
|
// generate the output
|
||||||
print_usage(true);
|
if (syscallsFile)
|
||||||
return 1;
|
_WriteSyscallsFile(syscallsFile);
|
||||||
}
|
if (dispatcherFile)
|
||||||
_ParseSyscalls(argv[1]);
|
_WriteDispatcherFile(dispatcherFile);
|
||||||
_WriteSyscallsFile(argv[2]);
|
|
||||||
_WriteDispatcherFile(argv[3]);
|
|
||||||
return 0;
|
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 _WriteSyscallsFile(const char *filename)
|
void _WriteSyscallsFile(const char *filename)
|
||||||
{
|
{
|
||||||
// open the syscalls output file
|
// open the syscalls output file
|
||||||
ofstream file(filename, ofstream::out | ofstream::trunc);
|
ofstream file(filename, ofstream::out | ofstream::trunc);
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
throw new IOException(string("Failed to open `") + filename + "'.");
|
throw IOException(string("Failed to open `") + filename + "'.");
|
||||||
// output the syscalls definitions
|
// output the syscalls definitions
|
||||||
for (int i = 0; i < (int)fSyscalls.size(); i++) {
|
for (int i = 0; i < fSyscallCount; i++) {
|
||||||
const Syscall &syscall = fSyscalls[i];
|
const gensyscall_syscall_info &syscall = fSyscallInfos[i];
|
||||||
file << "SYSCALL" << syscall.CountParameters() << "("
|
int paramCount = syscall.parameter_count;
|
||||||
<< syscall.GetName() << ", " << i << ")" << endl;
|
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
|
// open the dispatcher output file
|
||||||
ofstream file(filename, ofstream::out | ofstream::trunc);
|
ofstream file(filename, ofstream::out | ofstream::trunc);
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
throw new IOException(string("Failed to open `") + filename + "'.");
|
throw IOException(string("Failed to open `") + filename + "'.");
|
||||||
// output the case statements
|
// output the case statements
|
||||||
for (int i = 0; i < (int)fSyscalls.size(); i++) {
|
for (int i = 0; i < fSyscallCount; i++) {
|
||||||
const Syscall &syscall = fSyscalls[i];
|
const gensyscall_syscall_info &syscall = fSyscallInfos[i];
|
||||||
file << "case " << i << ":" << endl;
|
file << "case " << i << ":" << endl;
|
||||||
file << "\t";
|
file << "\t";
|
||||||
if (syscall.GetReturnType().type != "void")
|
if (string(syscall.return_type) != "void")
|
||||||
file << "*call_ret = ";
|
file << "*call_ret = ";
|
||||||
file << syscall.GetKernelName() << "(";
|
file << syscall.kernel_name << "(";
|
||||||
if (syscall.CountParameters() > 0) {
|
int paramCount = syscall.parameter_count;
|
||||||
file << "(" << syscall.ParameterAt(0).type << ")arg0";
|
if (paramCount > 0) {
|
||||||
for (int k = 1; k < (int)syscall.CountParameters(); k++)
|
gensyscall_parameter_info* parameters = syscall.parameters;
|
||||||
file << ", (" << syscall.ParameterAt(k).type << ")arg" << k;
|
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 << ");" << endl;
|
||||||
file << "\tbreak;" << endl;
|
file << "\tbreak;" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ParseSyscall(Tokenizer &tokenizer, Syscall &syscall)
|
static string _GetPointerType(const char *type)
|
||||||
{
|
{
|
||||||
// get return type and function name
|
char *parenthesis = strchr(type, ')');
|
||||||
vector<string> returnType;
|
if (!parenthesis)
|
||||||
while (tokenizer.GetNextToken() != "(") {
|
return string(type) + "*";
|
||||||
string token = tokenizer.GetCurrentToken();
|
// function pointer type
|
||||||
// strip leading "extern"
|
return string(type, parenthesis - type) + "*" + parenthesis;
|
||||||
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:
|
private:
|
||||||
vector<Syscall> fSyscalls;
|
const gensyscall_syscall_info *fSyscallInfos;
|
||||||
|
int fSyscallCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// main
|
// main
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
@@ -516,4 +150,3 @@ main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user