Skip to content
Snippets Groups Projects
Commit 0489a260 authored by Devon H. O'Dell's avatar Devon H. O'Dell Committed by Russ Cox
Browse files

FreeBSD-specific porting work.

cgo/libmach remain unimplemented. However, compilers, runtime,
and packages are 100%. I still need to go through and implement
missing syscalls (at least make sure they're all listed), but
for all shipped functionality, this is done. Ship! ;)

R=rsc, VenkateshSrinivas
https://golang.org/cl/152142
parent 30b1b9a3
Branches
Tags
No related merge requests found
Showing
with 659 additions and 7 deletions
......@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
set -e
make hello fib chain
gomake hello fib chain
echo '*' hello >run.out
./hello >>run.out
echo '*' fib >>run.out
......@@ -12,4 +12,4 @@ echo '*' fib >>run.out
echo '*' chain >>run.out
./chain >>run.out
diff run.out golden.out
make clean
gomake clean
......@@ -38,6 +38,7 @@
#define PADDR(a) ((uint32)(a) & ~0x80000000)
char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
char freebsddynld[] = "/libexec/ld-elf.so.1";
char zeroes[32];
......@@ -284,7 +285,7 @@ doelf(void)
Sym *s, *shstrtab, *dynamic, *dynstr, *d;
int h, nsym, t;
if(HEADTYPE != 7)
if(HEADTYPE != 7 && HEADTYPE != 9)
return;
/* predefine strings we need for section headers */
......@@ -317,7 +318,14 @@ doelf(void)
s = lookup(".interp", 0);
s->reachable = 1;
s->type = SDATA; // TODO: rodata
addstring(lookup(".interp", 0), linuxdynld);
switch(HEADTYPE) {
case 7:
addstring(lookup(".interp", 0), linuxdynld);
break;
case 9:
addstring(lookup(".interp", 0), freebsddynld);
break;
}
/*
* hash table.
......@@ -512,6 +520,7 @@ asmb(void)
break;
case 7:
case 9:
debug['8'] = 1; /* 64-bit addresses */
v = rnd(HEADR+textsize, INITRND);
seek(cout, v, 0);
......@@ -565,6 +574,7 @@ asmb(void)
symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
break;
case 7:
case 9:
symo = rnd(HEADR+textsize, INITRND)+datsize;
symo = rnd(symo, INITRND);
break;
......@@ -649,6 +659,7 @@ asmb(void)
asmbmacho(symdatva, symo);
break;
case 7:
case 9:
/* elf amd-64 */
eh = getElfEhdr();
......@@ -871,6 +882,8 @@ asmb(void)
eh->ident[EI_MAG1] = 'E';
eh->ident[EI_MAG2] = 'L';
eh->ident[EI_MAG3] = 'F';
if(HEADTYPE == 9)
eh->ident[EI_OSABI] = 9;
eh->ident[EI_CLASS] = ELFCLASS64;
eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
......
......@@ -46,6 +46,7 @@ char* paramspace = "FP";
* -H5 -T0x80110000 -R4096 is ELF32
* -H6 -Tx -Rx is apple MH-exec
* -H7 -Tx -Rx is linux elf-exec
* -H9 -Tx -Rx is FreeBSD elf-exec
*
* options used: 189BLQSWabcjlnpsvz
*/
......@@ -149,6 +150,10 @@ main(int argc, char *argv[])
if(strcmp(goos, "darwin") == 0)
HEADTYPE = 6;
else
if(strcmp(goos, "freebsd") == 0) {
debug['d'] = 1; /* no dynamic syms for now */
HEADTYPE = 9;
} else
print("goos is not known: %s\n", goos);
}
......@@ -194,6 +199,7 @@ main(int argc, char *argv[])
INITDAT = 0;
break;
case 7: /* elf64 executable */
case 9: /* freebsd */
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
......
......@@ -24,6 +24,7 @@ clean:
install: install-$(shell uname | tr A-Z a-z)
install-linux: install-default
install-freebsd: install-default
# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
install-darwin: $(TARG)
......
......@@ -24,6 +24,7 @@ clean:
install: install-$(shell uname | tr A-Z a-z)
install-linux: install-default
install-freebsd: install-default
# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
install-darwin: $(TARG)
......
......@@ -16,6 +16,7 @@ CFLAGS_amd64=-m64
LDFLAGS_linux=-shared -lpthread -lm
LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup /usr/lib/libpthread.dylib
LDFLAGS_freebsd=-pthread -shared -lm
%.o: %.c
gcc $(CFLAGS_$(GOARCH)) -O2 -fPIC -o $@ -c $*.c
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <pthread.h>
#include "libcgo.h"
static void* threadentry(void*);
void
initcgo(void)
{
}
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
pthread_t p;
size_t size;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
pthread_create(&p, &attr, threadentry, ts);
}
static void*
threadentry(void *v)
{
ThreadStart ts;
ts = *(ThreadStart*)v;
free(v);
ts.g->stackbase = (uintptr)&ts;
/*
* libcgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
crosscall_amd64(ts.m, ts.g, ts.fn);
return nil;
}
// This is stubbed out for the moment. Will revisit when the time comes.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
int
ctlproc(int pid, char *msg)
{
sysfatal("ctlproc unimplemented in FreeBSD");
}
char*
proctextfile(int pid)
{
sysfatal("proctextfile unimplemented in FreeBSD");
}
char*
procstatus(int pid)
{
sysfatal("procstatus unimplemented in FreeBSD");
}
Map*
attachproc(int pid, Fhdr *fp)
{
sysfatal("attachproc unimplemented in FreeBSD");
}
void
detachproc(Map *m)
{
sysfatal("detachproc unimplemented in FreeBSD");
}
int
procthreadpids(int pid, int *p, int np)
{
sysfatal("procthreadpids unimplemented in FreeBSD");
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proc
import "os"
// Process tracing is not supported on FreeBSD yet.
func Attach(pid int) (Process, os.Error) {
return nil, os.NewError("debug/proc not implemented on FreeBSD")
}
func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
return Attach(0)
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proc
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Waiting for FDs via kqueue/kevent.
package net
import (
"os";
"syscall";
)
type pollster struct {
kq int;
eventbuf [10]syscall.Kevent_t;
events []syscall.Kevent_t;
}
func newpollster() (p *pollster, err os.Error) {
p = new(pollster);
var e int;
if p.kq, e = syscall.Kqueue(); e != 0 {
return nil, os.NewSyscallError("kqueue", e)
}
p.events = p.eventbuf[0:0];
return p, nil;
}
func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
var kmode int;
if mode == 'r' {
kmode = syscall.EVFILT_READ
} else {
kmode = syscall.EVFILT_WRITE
}
var events [1]syscall.Kevent_t;
ev := &events[0];
// EV_ADD - add event to kqueue list
// EV_ONESHOT - delete the event the first time it triggers
flags := syscall.EV_ADD;
if !repeat {
flags |= syscall.EV_ONESHOT
}
syscall.SetKevent(ev, fd, kmode, flags);
n, e := syscall.Kevent(p.kq, &events, nil, nil);
if e != 0 {
return os.NewSyscallError("kevent", e)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
return os.NewSyscallError("kqueue phase error", e)
}
if ev.Data != 0 {
return os.Errno(int(ev.Data))
}
return nil;
}
func (p *pollster) DelFD(fd int, mode int) {
var kmode int;
if mode == 'r' {
kmode = syscall.EVFILT_READ
} else {
kmode = syscall.EVFILT_WRITE
}
var events [1]syscall.Kevent_t;
ev := &events[0];
// EV_DELETE - delete event from kqueue list
syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE);
syscall.Kevent(p.kq, &events, nil, nil);
}
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
var t *syscall.Timespec;
for len(p.events) == 0 {
if nsec > 0 {
if t == nil {
t = new(syscall.Timespec)
}
*t = syscall.NsecToTimespec(nsec);
}
nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t);
if e != 0 {
if e == syscall.EINTR {
continue
}
return -1, 0, os.NewSyscallError("kevent", e);
}
if nn == 0 {
return -1, 0, nil
}
p.events = p.eventbuf[0:nn];
}
ev := &p.events[0];
p.events = p.events[1:len(p.events)];
fd = int(ev.Ident);
if ev.Filter == syscall.EVFILT_READ {
mode = 'r'
} else {
mode = 'w'
}
return fd, mode, nil;
}
func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
......@@ -18,6 +18,10 @@ import (
// Unfortunately, we need to run on kernels built without IPv6 support too.
// So probe the kernel to figure it out.
func kernelSupportsIPv6() bool {
// FreeBSD does not support this sort of interface.
if syscall.OS == "freebsd" {
return false
}
fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP);
if fd >= 0 {
syscall.Close(fd)
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import (
"syscall";
"unsafe";
)
const (
blockSize = 4096; // TODO(r): use statfs
)
func (file *File) Readdirnames(count int) (names []string, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = new(dirInfo);
// The buffer must be at least a block long.
// TODO(r): use fstatfs to find fs block size.
file.dirinfo.buf = make([]byte, blockSize);
}
d := file.dirinfo;
size := count;
if size < 0 {
size = 100
}
names = make([]string, 0, size); // Empty with room to grow.
for count != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
var errno int;
d.bufp = 0;
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
d.nbuf, errno = syscall.Getdirentries(file.fd, d.buf, new(uintptr));
if errno != 0 {
d.nbuf = 0;
return names, NewSyscallError("getdirentries", errno);
}
if d.nbuf <= 0 {
break // EOF
}
}
// Drain the buffer
for count != 0 && d.bufp < d.nbuf {
dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp]));
if dirent.Reclen == 0 {
d.bufp = d.nbuf;
break;
}
d.bufp += int(dirent.Reclen);
if dirent.Fileno == 0 { // File absent in directory.
continue
}
bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]));
var name = string(bytes[0:dirent.Namlen]);
if name == "." || name == ".." { // Useless names
continue
}
count--;
if len(names) == cap(names) {
nnames := make([]string, len(names), 2*len(names));
for i := 0; i < len(names); i++ {
nnames[i] = names[i]
}
names = nnames;
}
names = names[0 : len(names)+1];
names[len(names)-1] = name;
}
}
return names, nil;
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import "syscall"
func isSymlink(stat *syscall.Stat_t) bool {
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
}
func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir {
dir.Dev = uint64(stat.Dev);
dir.Ino = uint64(stat.Ino);
dir.Nlink = uint64(stat.Nlink);
dir.Mode = uint32(stat.Mode);
dir.Uid = stat.Uid;
dir.Gid = stat.Gid;
dir.Rdev = uint64(stat.Rdev);
dir.Size = uint64(stat.Size);
dir.Blksize = uint64(stat.Blksize);
dir.Blocks = uint64(stat.Blocks);
dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atimespec));
dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtimespec));
dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctimespec));
for i := len(name) - 1; i >= 0; i-- {
if name[i] == '/' {
name = name[i+1 : len(name)];
break;
}
}
dir.Name = name;
if isSymlink(lstat) && !isSymlink(stat) {
dir.FollowedSymlink = true
}
return dir;
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import "syscall"
func Hostname() (name string, err Error) {
var errno int;
name, errno = syscall.Sysctl("kern.hostname");
if errno != 0 {
return "", NewSyscallError("sysctl kern.hostname", errno)
}
return name, nil;
}
......@@ -5,10 +5,9 @@
#include "amd64/asm.h"
TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack
MOVQ 0(SP), AX // argc
LEAQ 8(SP), BX // argv
MOVQ 0(DI), AX // argc
LEAQ 8(DI), BX // argv
SUBQ $(4*8+7), SP // 2args 2auto
ANDQ $~7, SP
MOVQ AX, 16(SP)
......
......@@ -6,4 +6,5 @@
TEXT _rt0_amd64_darwin(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
MOVQ SP, DI
JMP AX
// godefs -f -m64 freebsd/defs.c
// MACHINE GENERATED - DO NOT EDIT.
// Constants
enum {
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
UMTX_OP_WAIT = 0x2,
UMTX_OP_WAKE = 0x3,
EINTR = 0x4,
};
// Types
#pragma pack on
typedef struct Sigaltstack Sigaltstack;
struct Sigaltstack {
int8 *ss_sp;
uint64 ss_size;
int32 ss_flags;
byte pad0[4];
};
typedef struct Sigset Sigset;
struct Sigset {
uint32 __bits[4];
};
typedef union Sigval Sigval;
union Sigval {
int32 sival_int;
void *sival_ptr;
int32 sigval_int;
void *sigval_ptr;
};
typedef struct StackT StackT;
struct StackT {
int8 *ss_sp;
uint64 ss_size;
int32 ss_flags;
byte pad0[4];
};
typedef struct Siginfo Siginfo;
struct Siginfo {
int32 si_signo;
int32 si_errno;
int32 si_code;
int32 si_pid;
uint32 si_uid;
int32 si_status;
void *si_addr;
Sigval si_value;
byte _reason[40];
};
typedef struct Mcontext Mcontext;
struct Mcontext {
int64 mc_onstack;
int64 mc_rdi;
int64 mc_rsi;
int64 mc_rdx;
int64 mc_rcx;
int64 mc_r8;
int64 mc_r9;
int64 mc_rax;
int64 mc_rbx;
int64 mc_rbp;
int64 mc_r10;
int64 mc_r11;
int64 mc_r12;
int64 mc_r13;
int64 mc_r14;
int64 mc_r15;
uint32 mc_trapno;
uint16 mc_fs;
uint16 mc_gs;
int64 mc_addr;
uint32 mc_flags;
uint16 mc_es;
uint16 mc_ds;
int64 mc_err;
int64 mc_rip;
int64 mc_cs;
int64 mc_rflags;
int64 mc_rsp;
int64 mc_ss;
int64 mc_len;
int64 mc_fpformat;
int64 mc_ownedfp;
int64 mc_fpstate[64];
int64 mc_fsbase;
int64 mc_gsbase;
int64 mc_spare[6];
};
typedef struct Ucontext Ucontext;
struct Ucontext {
Sigset uc_sigmask;
Mcontext uc_mcontext;
Ucontext *uc_link;
StackT uc_stack;
int32 uc_flags;
int32 __spare__[4];
byte pad0[12];
};
typedef struct Sigcontext Sigcontext;
struct Sigcontext {
Sigset sc_mask;
int64 sc_onstack;
int64 sc_rdi;
int64 sc_rsi;
int64 sc_rdx;
int64 sc_rcx;
int64 sc_r8;
int64 sc_r9;
int64 sc_rax;
int64 sc_rbx;
int64 sc_rbp;
int64 sc_r10;
int64 sc_r11;
int64 sc_r12;
int64 sc_r13;
int64 sc_r14;
int64 sc_r15;
int32 sc_trapno;
int16 sc_fs;
int16 sc_gs;
int64 sc_addr;
int32 sc_flags;
int16 sc_es;
int16 sc_ds;
int64 sc_err;
int64 sc_rip;
int64 sc_cs;
int64 sc_rflags;
int64 sc_rsp;
int64 sc_ss;
int64 sc_len;
int64 sc_fpformat;
int64 sc_ownedfp;
int64 sc_fpstate[64];
int64 sc_fsbase;
int64 sc_gsbase;
int64 sc_spare[6];
};
#pragma pack off
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Darwin and Linux use the same linkage to main
TEXT _rt0_amd64_freebsd(SB),7,$-8
MOVQ $_rt0_amd64(SB), DX
JMP DX
#include "runtime.h"
#include "defs.h"
#include "signals.h"
#include "os.h"
extern void sigtramp(void);
typedef struct sigaction {
union {
void (*__sa_handler)(int32);
void (*__sa_sigaction)(int32, Siginfo*, void *);
} __sigaction_u; /* signal handler */
int32 sa_flags; /* see signal options below */
int64 sa_mask; /* signal mask to apply */
} Sigaction;
void
dumpregs(Sigcontext *r)
{
printf("rax %X\n", r->sc_rax);
printf("rbx %X\n", r->sc_rbx);
printf("rcx %X\n", r->sc_rcx);
printf("rdx %X\n", r->sc_rdx);
printf("rdi %X\n", r->sc_rdi);
printf("rsi %X\n", r->sc_rsi);
printf("rbp %X\n", r->sc_rbp);
printf("rsp %X\n", r->sc_rsp);
printf("r8 %X\n", r->sc_r8 );
printf("r9 %X\n", r->sc_r9 );
printf("r10 %X\n", r->sc_r10);
printf("r11 %X\n", r->sc_r11);
printf("r12 %X\n", r->sc_r12);
printf("r13 %X\n", r->sc_r13);
printf("r14 %X\n", r->sc_r14);
printf("r15 %X\n", r->sc_r15);
printf("rip %X\n", r->sc_rip);
printf("rflags %X\n", r->sc_flags);
printf("cs %X\n", (uint64)r->sc_cs);
printf("fs %X\n", (uint64)r->sc_fsbase);
printf("gs %X\n", (uint64)r->sc_gsbase);
}
void
sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
Sigcontext *sc;
if(panicking) // traceback already printed
exit(2);
panicking = 1;
uc = context;
mc = &uc->uc_mcontext;
sc = (Sigcontext*)mc; // same layout, more conveient names
if(sig < 0 || sig >= NSIG)
printf("Signal %d\n", sig);
else
printf("%s\n", sigtab[sig].name);
printf("Faulting address: %p\n", info->si_addr);
printf("PC=%X\n", sc->sc_rip);
printf("\n");
if(gotraceback()){
traceback((void*)sc->sc_rip, (void*)sc->sc_rsp, (void*)sc->sc_r15);
tracebackothers((void*)sc->sc_r15);
dumpregs(sc);
}
breakpoint();
exit(2);
}
void
sigignore(void)
{
}
void
signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
sigaltstack(&st, nil);
}
void
initsig(void)
{
static Sigaction sa;
int32 i;
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
sa.sa_mask = ~0x0ull;
for(i = 0; i < NSIG; i++) {
if(sigtab[i].flags) {
if(sigtab[i].flags & SigCatch)
sa.__sigaction_u.__sa_handler = (void*) sigtramp;
else
sa.__sigaction_u.__sa_handler = (void*) sigignore;
if(sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
sigaction(i, &sa, nil);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment