Blame hurd/hurdstartup.c

Packit Service 82fcde
/* Initial program startup for running under the GNU Hurd.
Packit Service 82fcde
   Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <hurd.h>
Packit Service 82fcde
#include <hurd/exec_startup.h>
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <elf.h>
Packit Service 82fcde
#include <set-hooks.h>
Packit Service 82fcde
#include "hurdstartup.h"
Packit Service 82fcde
#include <argz.h>
Packit Service 82fcde
Packit Service 82fcde
mach_port_t *_hurd_init_dtable;
Packit Service 82fcde
mach_msg_type_number_t _hurd_init_dtablesize;
Packit Service 82fcde
Packit Service 82fcde
extern void __mach_init (void);
Packit Service 82fcde
Packit Service 82fcde
/* Entry point.  This is the first thing in the text segment.
Packit Service 82fcde
Packit Service 82fcde
   The exec server started the initial thread in our task with this spot the
Packit Service 82fcde
   PC, and a stack that is presumably big enough.  We do basic Mach
Packit Service 82fcde
   initialization so mig-generated stubs work, and then do an exec_startup
Packit Service 82fcde
   RPC on our bootstrap port, to which the exec server responds with the
Packit Service 82fcde
   information passed in the exec call, as well as our original bootstrap
Packit Service 82fcde
   port, and the base address and size of the preallocated stack.
Packit Service 82fcde
Packit Service 82fcde
   If using cthreads, we are given a new stack by cthreads initialization and
Packit Service 82fcde
   deallocate the stack set up by the exec server.  On the new stack we call
Packit Service 82fcde
   `start1' (above) to do the rest of the startup work.  Since the stack may
Packit Service 82fcde
   disappear out from under us in a machine-dependent way, we use a pile of
Packit Service 82fcde
   static variables to communicate the information from exec_startup to start1.
Packit Service 82fcde
   This is unfortunate but preferable to machine-dependent frobnication to copy
Packit Service 82fcde
   the state from the old stack to the new one.  */
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_hurd_startup (void **argptr, void (*main) (intptr_t *data))
Packit Service 82fcde
{
Packit Service 82fcde
  error_t err;
Packit Service 82fcde
  mach_port_t in_bootstrap;
Packit Service 82fcde
  char *args, *env;
Packit Service 82fcde
  mach_msg_type_number_t argslen, envlen;
Packit Service 82fcde
  struct hurd_startup_data data;
Packit Service 82fcde
  char **argv, **envp;
Packit Service 82fcde
  int argc, envc;
Packit Service 82fcde
  intptr_t *argcptr;
Packit Service 82fcde
  vm_address_t addr;
Packit Service 82fcde
Packit Service 82fcde
  /* Attempt to map page zero redzoned before we receive any RPC
Packit Service 82fcde
     data that might get allocated there.  We can ignore errors.  */
Packit Service 82fcde
  addr = 0;
Packit Service 82fcde
  __vm_map (__mach_task_self (),
Packit Service 82fcde
	    &addr, __vm_page_size, 0, 0, MACH_PORT_NULL, 0, 1,
Packit Service 82fcde
	    VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
Packit Service 82fcde
Packit Service 82fcde
  if (err = __task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
Packit Service 82fcde
				     &in_bootstrap))
Packit Service 82fcde
    LOSE;
Packit Service 82fcde
Packit Service 82fcde
  if (in_bootstrap != MACH_PORT_NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Call the exec server on our bootstrap port and
Packit Service 82fcde
	 get all our standard information from it.  */
Packit Service 82fcde
Packit Service 82fcde
      argslen = envlen = 0;
Packit Service 82fcde
      data.dtablesize = data.portarraysize = data.intarraysize = 0;
Packit Service 82fcde
Packit Service 82fcde
      err = __exec_startup_get_info (in_bootstrap,
Packit Service 82fcde
				     &data.user_entry,
Packit Service 82fcde
				     &data.phdr, &data.phdrsz,
Packit Service 82fcde
				     &data.stack_base, &data.stack_size,
Packit Service 82fcde
				     &data.flags,
Packit Service 82fcde
				     &args, &argslen,
Packit Service 82fcde
				     &env, &envlen,
Packit Service 82fcde
				     &data.dtable, &data.dtablesize,
Packit Service 82fcde
				     &data.portarray, &data.portarraysize,
Packit Service 82fcde
				     &data.intarray, &data.intarraysize);
Packit Service 82fcde
      __mach_port_deallocate (__mach_task_self (), in_bootstrap);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (err || in_bootstrap == MACH_PORT_NULL || (data.flags & EXEC_STACK_ARGS))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Either we have no bootstrap port, or the RPC to the exec server
Packit Service 82fcde
	 failed, or whoever started us up passed the flag saying args are
Packit Service 82fcde
	 on the stack.  Try to snarf the args in the canonical Mach way.
Packit Service 82fcde
	 Hopefully either they will be on the stack as expected, or the
Packit Service 82fcde
	 stack will be zeros so we don't crash.  */
Packit Service 82fcde
Packit Service 82fcde
      argcptr = (intptr_t *) argptr;
Packit Service 82fcde
      argc = argcptr[0];
Packit Service 82fcde
      argv = (char **) &argcptr[1];
Packit Service 82fcde
      envp = &argv[argc + 1];
Packit Service 82fcde
      envc = 0;
Packit Service 82fcde
      while (envp[envc])
Packit Service 82fcde
	++envc;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Turn the block of null-separated strings we were passed for the
Packit Service 82fcde
	 arguments and environment into vectors of pointers to strings.  */
Packit Service 82fcde
Packit Service 82fcde
      /* Count up the arguments so we can allocate ARGV.  */
Packit Service 82fcde
      argc = __argz_count (args, argslen);
Packit Service 82fcde
      /* Count up the environment variables so we can allocate ENVP.  */
Packit Service 82fcde
      envc = __argz_count (env, envlen);
Packit Service 82fcde
Packit Service 82fcde
      /* There were some arguments.  Allocate space for the vectors of
Packit Service 82fcde
	 pointers and fill them in.  We allocate the space for the
Packit Service 82fcde
	 environment pointers immediately after the argv pointers because
Packit Service 82fcde
	 the ELF ABI will expect it.  */
Packit Service 82fcde
      argcptr = __alloca (sizeof (intptr_t) +
Packit Service 82fcde
			  (argc + 1 + envc + 1) * sizeof (char *) +
Packit Service 82fcde
			  sizeof (struct hurd_startup_data));
Packit Service 82fcde
      *argcptr = argc;
Packit Service 82fcde
      argv = (void *) (argcptr + 1);
Packit Service 82fcde
      __argz_extract (args, argslen, argv);
Packit Service 82fcde
Packit Service 82fcde
      /* There was some environment.  */
Packit Service 82fcde
      envp = &argv[argc + 1];
Packit Service 82fcde
      __argz_extract (env, envlen, envp);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (err || in_bootstrap == MACH_PORT_NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Either we have no bootstrap port, or the RPC to the exec server
Packit Service 82fcde
	 failed.  Set all our other variables to have empty information.  */
Packit Service 82fcde
Packit Service 82fcde
      data.flags = 0;
Packit Service 82fcde
      args = env = NULL;
Packit Service 82fcde
      argslen = envlen = 0;
Packit Service 82fcde
      data.dtable = NULL;
Packit Service 82fcde
      data.dtablesize = 0;
Packit Service 82fcde
      data.portarray = NULL;
Packit Service 82fcde
      data.portarraysize = 0;
Packit Service 82fcde
      data.intarray = NULL;
Packit Service 82fcde
      data.intarraysize = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  else if ((void *) &envp[envc + 1] == argv[0])
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The arguments arrived on the stack from the kernel, but our
Packit Service 82fcde
	 protocol requires some space after them for a `struct
Packit Service 82fcde
	 hurd_startup_data'.  Move them.  */
Packit Service 82fcde
      struct
Packit Service 82fcde
	{
Packit Service 82fcde
	  intptr_t count;
Packit Service 82fcde
	  char *argv[argc + 1];
Packit Service 82fcde
	  char *envp[envc + 1];
Packit Service 82fcde
	  struct hurd_startup_data data;
Packit Service 82fcde
	} *args = alloca (sizeof *args);
Packit Service 82fcde
      if ((void *) &args[1] == (void *) argcptr)
Packit Service 82fcde
	args = alloca (-((char *) &args->data - (char *) args));
Packit Service 82fcde
      memmove (args, argcptr, (char *) &args->data - (char *) args);
Packit Service 82fcde
      argcptr = (void *) args;
Packit Service 82fcde
      argv = args->argv;
Packit Service 82fcde
      envp = args->envp;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  {
Packit Service 82fcde
    struct hurd_startup_data *d = (void *) &envp[envc + 1];
Packit Service 82fcde
Packit Service 82fcde
    if ((void *) d != argv[0])
Packit Service 82fcde
      {
Packit Service 82fcde
	*d = data;
Packit Service 82fcde
	_hurd_init_dtable = d->dtable;
Packit Service 82fcde
	_hurd_init_dtablesize = d->dtablesize;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
    (*main) (argcptr);
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  /* Should never get here.  */
Packit Service 82fcde
  LOSE;
Packit Service 82fcde
  abort ();
Packit Service 82fcde
}