386 lines
9.4 KiB
Go
386 lines
9.4 KiB
Go
/*
|
|
* This file is part of Jehanne.
|
|
*
|
|
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
*
|
|
* Jehanne is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"text/template"
|
|
)
|
|
|
|
type SyscallConf struct {
|
|
Ret []string
|
|
Args []string
|
|
Name string
|
|
Id uint32
|
|
}
|
|
|
|
type Sysconf struct {
|
|
Syscalls []SyscallConf
|
|
}
|
|
|
|
func usage(msg string) {
|
|
fmt.Fprint(os.Stderr, msg)
|
|
fmt.Fprint(os.Stderr, "Usage: ksyscalls path/to/sysconf.json\n")
|
|
flag.PrintDefaults()
|
|
os.Exit(1)
|
|
}
|
|
|
|
type SyscallWrapper struct {
|
|
Id uint32
|
|
Name string
|
|
Vars []string
|
|
CommonCode string
|
|
ExecCode string
|
|
EntryPrint string
|
|
ExitPrint string
|
|
SysRetField string
|
|
DefaultRet string
|
|
}
|
|
|
|
type KernelCode struct {
|
|
Externs []string
|
|
Wrappers []SyscallWrapper
|
|
}
|
|
|
|
func uregArg(index int) string{
|
|
switch(index){
|
|
case 0:
|
|
return "di";
|
|
case 1:
|
|
return "si";
|
|
case 2:
|
|
return "dx";
|
|
case 3:
|
|
return "r10";
|
|
case 4:
|
|
return "r8";
|
|
case 5:
|
|
return "r9";
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func sysret(t string) string {
|
|
switch(t){
|
|
case "int", "int32_t":
|
|
return "i"
|
|
case "long", "int64_t":
|
|
return "vl"
|
|
case "uintptr_t", "void":
|
|
return "p"
|
|
case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*":
|
|
return "v"
|
|
}
|
|
return " [?? " + t + "]"
|
|
}
|
|
|
|
func formatArg(i int, t string) string{
|
|
switch(t){
|
|
case "int", "int32_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%d\", a%d);\n", i)
|
|
case "unsigned int", "uint32_t":
|
|
/* unsigned int is reserved for flags */
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#ux\", a%d);\n", i)
|
|
case "long", "int64_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%lld\", a%d);\n", i)
|
|
case "unsigned long", "uint64_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#lud\", a%d);\n", i)
|
|
case "void*", "uint8_t*", "const void*", "const uint8_t*":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p\", a%d);\n", i)
|
|
case "int32_t*", "int*", "const int32_t*", "const int*":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p(%%d)\", a%d, a%d);\n", i, i)
|
|
case "const char*", "char*":
|
|
return fmt.Sprintf("\tfmtuserstring(fmt, a%d);\n", i)
|
|
case "const char**", "char**":
|
|
return fmt.Sprintf("\tfmtuserstringlist(fmt, a%d);\n", i);
|
|
}
|
|
return " [?? " + t + "]"
|
|
}
|
|
|
|
func formatRet(t string) string{
|
|
switch(t){
|
|
case "int", "int32_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%d\", ret->%s);\n", sysret(t))
|
|
case "unsigned int", "uint32_t":
|
|
/* unsigned int is reserved for flags */
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#ux\", ret->%s);\n", sysret(t))
|
|
case "long", "int64_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%lld\", ret->%s);\n", sysret(t))
|
|
case "unsigned long", "uint64_t", "void":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#llud\", ret->%s);\n", sysret(t))
|
|
case "void*", "uintptr_t", "const void*", "const uintptr_t":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p\", ret->%s);\n", sysret(t))
|
|
case "int32_t*", "int*", "const int32_t*", "const int*":
|
|
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p(%%d)\", ret->%s, *ret->%s);\n", sysret(t), sysret(t))
|
|
}
|
|
return " [?? " + t + "]"
|
|
}
|
|
|
|
func generateKernelCode(calls []SyscallConf){
|
|
code := new(KernelCode)
|
|
|
|
for _, call := range(calls) {
|
|
/* extern definitions */
|
|
ext := "extern " + call.Ret[0] + " sys" + call.Name + "("
|
|
if len(call.Args) == 0 {
|
|
ext += "void";
|
|
} else {
|
|
for i, a := range(call.Args){
|
|
if i > 0 {
|
|
ext += ", "
|
|
}
|
|
ext += fmt.Sprintf("%s", a)
|
|
}
|
|
}
|
|
ext += ");\n"
|
|
|
|
wcall := new(SyscallWrapper)
|
|
wcall.Id = call.Id
|
|
wcall.Name = call.Name
|
|
wcall.SysRetField = sysret(call.Ret[0])
|
|
wcall.DefaultRet = fmt.Sprintf("ret.%s = (%s)-1;", wcall.SysRetField, call.Ret[0])
|
|
|
|
for i, a := range(call.Args){
|
|
wcall.Vars = append(wcall.Vars, fmt.Sprintf("%s a%v;", a, i))
|
|
wcall.CommonCode += fmt.Sprintf("\ta%v = (%s)ureg->%s;\n", i, a, uregArg(i))
|
|
}
|
|
wcall.ExecCode += "\tret->" + wcall.SysRetField + " = sys" + call.Name + "("
|
|
for i, _ := range(call.Args){
|
|
if i > 0 {
|
|
wcall.ExecCode += ", "
|
|
}
|
|
wcall.ExecCode += fmt.Sprintf("a%v", i)
|
|
}
|
|
wcall.ExecCode += ");"
|
|
|
|
if call.Name == "pwrite"{
|
|
wcall.EntryPrint += formatArg(0, call.Args[0])
|
|
wcall.EntryPrint += "\tfmtrwdata(fmt, (char*)a1, MIN(a2, 64));\n"
|
|
wcall.EntryPrint += formatArg(2, call.Args[2])
|
|
wcall.EntryPrint += formatArg(3, call.Args[3])
|
|
} else {
|
|
for i, a := range(call.Args){
|
|
wcall.EntryPrint += formatArg(i, a)
|
|
}
|
|
}
|
|
|
|
wcall.ExitPrint += formatRet(call.Ret[0])
|
|
if call.Name == "pread"{
|
|
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(1), uregArg(2))
|
|
} else if call.Name == "fd2path"{
|
|
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(1), uregArg(2))
|
|
} else if call.Name == "await"{
|
|
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(0), uregArg(1))
|
|
} else if call.Name == "errstr"{
|
|
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(0), uregArg(1))
|
|
}
|
|
|
|
code.Wrappers = append(code.Wrappers, *wcall)
|
|
code.Externs = append(code.Externs, ext)
|
|
}
|
|
|
|
tmpl, err := template.New("systab.c").Parse(`/*
|
|
* This file is part of Jehanne.
|
|
*
|
|
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
*
|
|
* Jehanne is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/* automatically generated by ksyscalls */
|
|
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "../port/error.h"
|
|
#include "ureg.h"
|
|
|
|
extern void fmtrwdata(Fmt* f, char* a, int n);
|
|
extern void fmtuserstring(Fmt* f, const char* a);
|
|
extern void fmtuserstringlist(Fmt* f, const char** argv);
|
|
|
|
{{ range .Externs }}{{.}}{{ end }}
|
|
{{ range .Wrappers }}
|
|
static void
|
|
wrap_{{ .Name }}(ScRet* ret, Ureg* ureg)
|
|
{
|
|
{{ range .Vars }}{{.}}
|
|
{{ end }}
|
|
{{ .CommonCode }}
|
|
{{ .ExecCode }}
|
|
}
|
|
{{ end }}
|
|
int nsyscall = {{len .Wrappers}};
|
|
|
|
ScRet
|
|
default_syscall_ret(int syscall)
|
|
{
|
|
static ScRet zero;
|
|
ScRet ret = zero;
|
|
switch(syscall){
|
|
{{ range .Wrappers }}case {{ .Id }}:
|
|
{{ .DefaultRet }}
|
|
break;
|
|
{{ end }}
|
|
default:
|
|
ret.vl = -1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
char*
|
|
syscall_name(int syscall)
|
|
{
|
|
switch(syscall){
|
|
{{ range .Wrappers }}case {{ .Id }}:
|
|
return "{{ .Name }}";
|
|
{{ end }}
|
|
default:
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
void
|
|
dispatch_syscall(int syscall, Ureg* ureg, ScRet* ret)
|
|
{
|
|
switch(syscall){
|
|
{{ range .Wrappers }}case {{ .Id }}:
|
|
wrap_{{ .Name }}(ret, ureg);
|
|
break;
|
|
{{ end }}
|
|
default:
|
|
panic("dispatch_syscall: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
}
|
|
}
|
|
|
|
{{ range .Wrappers }}
|
|
static void
|
|
enter_{{ .Name }}(Fmt* fmt, Ureg* ureg)
|
|
{
|
|
{{ range .Vars }}{{.}}
|
|
{{ end }}
|
|
{{ .CommonCode }}
|
|
jehanne_fmtprint(fmt, "{{ .Name }} %#p >", ureg->ip);
|
|
if(up->notified)
|
|
jehanne_fmtprint(fmt, "!");
|
|
{{ .EntryPrint }}
|
|
jehanne_fmtprint(fmt, "\n");
|
|
}
|
|
{{ end }}
|
|
|
|
char*
|
|
syscallfmt(int syscall, Ureg* ureg)
|
|
{
|
|
Fmt fmt;
|
|
jehanne_fmtstrinit(&fmt);
|
|
jehanne_fmtprint(&fmt, "%d %s ", up->pid, up->text);
|
|
|
|
switch(syscall){
|
|
{{ range .Wrappers }}case {{ .Id }}:
|
|
enter_{{ .Name }}(&fmt, ureg);
|
|
break;
|
|
{{ end }}
|
|
default:
|
|
panic("syscallfmt: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
}
|
|
|
|
return jehanne_fmtstrflush(&fmt);
|
|
}
|
|
|
|
{{ range .Wrappers }}
|
|
static void
|
|
exit_{{ .Name }}(Fmt* fmt, Ureg* ureg, ScRet* ret)
|
|
{
|
|
jehanne_fmtprint(fmt, "{{ .Name }} %#p <", ureg->ip);
|
|
if(up->notified)
|
|
jehanne_fmtprint(fmt, "!");
|
|
{{ .ExitPrint }}
|
|
}
|
|
{{ end }}
|
|
|
|
char*
|
|
sysretfmt(int syscall, Ureg* ureg, ScRet* ret, uint64_t start, uint64_t stop)
|
|
{
|
|
Fmt fmt;
|
|
jehanne_fmtstrinit(&fmt);
|
|
jehanne_fmtprint(&fmt, "%d %s ", up->pid, up->text);
|
|
|
|
switch(syscall){
|
|
{{ range .Wrappers }}case {{ .Id }}:
|
|
exit_{{ .Name }}(&fmt, ureg, ret);
|
|
break;
|
|
{{ end }}
|
|
default:
|
|
panic("sysretfmt: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
}
|
|
|
|
if(0 > ret->vl){
|
|
jehanne_fmtprint(&fmt, " %s %#llud %#llud\n", up->syserrstr, start, stop-start);
|
|
} else {
|
|
jehanne_fmtprint(&fmt, " \"\" %#llud %#llud\n", start, stop-start);
|
|
}
|
|
|
|
return jehanne_fmtstrflush(&fmt);
|
|
}
|
|
|
|
`)
|
|
err = tmpl.Execute(os.Stdout, code)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
if flag.NArg() != 1 {
|
|
usage("no path to sysconf.json")
|
|
}
|
|
|
|
buf, err := ioutil.ReadFile(flag.Arg(0))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var sysconf Sysconf
|
|
err = json.Unmarshal(buf, &sysconf)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
generateKernelCode(sysconf.Syscalls)
|
|
|
|
}
|