1996-07-24 05:58:12 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
|
|
|
/* Objective Caml */
|
|
|
|
/* */
|
|
|
|
/* Xavier Leroy and Damien Doligez, INRIA Rocquencourt */
|
|
|
|
/* */
|
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1996-07-24 05:58:12 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
/* Start-up code */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAS_UNISTD
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2000-04-04 06:19:12 -07:00
|
|
|
#ifdef _WIN32
|
2001-04-10 04:14:33 -07:00
|
|
|
#include <process.h>
|
2000-04-04 06:19:12 -07:00
|
|
|
#endif
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "alloc.h"
|
2001-02-19 04:29:00 -08:00
|
|
|
#include "backtrace.h"
|
1999-02-14 08:48:25 -08:00
|
|
|
#include "callback.h"
|
2000-02-11 07:09:27 -08:00
|
|
|
#include "custom.h"
|
1996-11-29 10:36:42 -08:00
|
|
|
#include "debugger.h"
|
2001-08-28 07:47:48 -07:00
|
|
|
#include "dynlink.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "exec.h"
|
|
|
|
#include "fail.h"
|
|
|
|
#include "fix_code.h"
|
2008-12-03 10:09:09 -08:00
|
|
|
#include "freelist.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "gc_ctrl.h"
|
2001-02-19 04:29:00 -08:00
|
|
|
#include "instrtrace.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "interp.h"
|
|
|
|
#include "intext.h"
|
|
|
|
#include "io.h"
|
1997-06-13 08:49:36 -07:00
|
|
|
#include "memory.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "minor_gc.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "mlvalues.h"
|
2001-08-28 07:47:48 -07:00
|
|
|
#include "osdeps.h"
|
1997-06-13 08:49:36 -07:00
|
|
|
#include "prims.h"
|
2001-06-15 07:22:38 -07:00
|
|
|
#include "printexc.h"
|
2000-03-06 01:29:33 -08:00
|
|
|
#include "reverse.h"
|
2000-01-31 21:41:23 -08:00
|
|
|
#include "signals.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
#include "stacks.h"
|
|
|
|
#include "sys.h"
|
2001-02-19 04:29:00 -08:00
|
|
|
#include "startup.h"
|
2004-11-26 17:04:19 -08:00
|
|
|
#include "version.h"
|
1996-07-24 05:58:12 -07:00
|
|
|
|
|
|
|
#ifndef O_BINARY
|
|
|
|
#define O_BINARY 0
|
|
|
|
#endif
|
|
|
|
|
1997-06-13 08:49:36 -07:00
|
|
|
#ifndef SEEK_END
|
|
|
|
#define SEEK_END 2
|
|
|
|
#endif
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
extern int caml_parser_trace;
|
2001-11-05 05:34:42 -08:00
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
CAMLexport header_t caml_atom_table[256];
|
1996-11-07 02:57:59 -08:00
|
|
|
|
|
|
|
/* Initialize the atom table */
|
1996-07-24 05:58:12 -07:00
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void init_atoms(void)
|
1996-07-24 05:58:12 -07:00
|
|
|
{
|
|
|
|
int i;
|
2003-12-31 06:20:40 -08:00
|
|
|
for(i = 0; i < 256; i++) caml_atom_table[i] = Make_header(0, i, Caml_white);
|
2008-01-03 01:37:10 -08:00
|
|
|
if (caml_page_table_add(In_static_data,
|
|
|
|
caml_atom_table, caml_atom_table + 256) != 0) {
|
|
|
|
caml_fatal_error("Fatal error: not enough memory for the initial page table");
|
|
|
|
}
|
1996-07-24 05:58:12 -07:00
|
|
|
}
|
|
|
|
|
1996-11-07 02:57:59 -08:00
|
|
|
/* Read the trailer of a bytecode file */
|
|
|
|
|
2000-03-05 11:18:50 -08:00
|
|
|
static void fixup_endianness_trailer(uint32 * p)
|
1996-07-24 05:58:12 -07:00
|
|
|
{
|
2000-03-05 11:18:50 -08:00
|
|
|
#ifndef ARCH_BIG_ENDIAN
|
|
|
|
Reverse_32(p, p);
|
|
|
|
#endif
|
|
|
|
}
|
1996-07-24 05:58:12 -07:00
|
|
|
|
2000-03-05 11:18:50 -08:00
|
|
|
static int read_trailer(int fd, struct exec_trailer *trail)
|
|
|
|
{
|
1997-06-13 08:49:36 -07:00
|
|
|
lseek(fd, (long) -TRAILER_SIZE, SEEK_END);
|
2000-03-05 11:18:50 -08:00
|
|
|
if (read(fd, (char *) trail, TRAILER_SIZE) < TRAILER_SIZE)
|
2001-02-19 02:01:41 -08:00
|
|
|
return BAD_BYTECODE;
|
2000-03-05 11:18:50 -08:00
|
|
|
fixup_endianness_trailer(&trail->num_sections);
|
|
|
|
if (strncmp(trail->magic, EXEC_MAGIC, 12) == 0)
|
1996-07-24 05:58:12 -07:00
|
|
|
return 0;
|
|
|
|
else
|
2001-02-19 02:01:41 -08:00
|
|
|
return BAD_BYTECODE;
|
1996-07-24 05:58:12 -07:00
|
|
|
}
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
int caml_attempt_open(char **name, struct exec_trailer *trail,
|
|
|
|
int do_open_script)
|
1996-07-24 05:58:12 -07:00
|
|
|
{
|
|
|
|
char * truename;
|
|
|
|
int fd;
|
|
|
|
int err;
|
|
|
|
char buf [2];
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
truename = caml_search_exe_in_path(*name);
|
2001-08-28 07:47:48 -07:00
|
|
|
*name = truename;
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_gc_message(0x100, "Opening bytecode executable %s\n",
|
2005-09-22 07:21:50 -07:00
|
|
|
(uintnat) truename);
|
1996-07-24 05:58:12 -07:00
|
|
|
fd = open(truename, O_RDONLY | O_BINARY);
|
2001-02-19 02:01:41 -08:00
|
|
|
if (fd == -1) {
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_gc_message(0x100, "Cannot open file\n", 0);
|
2001-02-19 02:01:41 -08:00
|
|
|
return FILE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
if (!do_open_script) {
|
1996-07-24 05:58:12 -07:00
|
|
|
err = read (fd, buf, 2);
|
2001-02-19 02:01:41 -08:00
|
|
|
if (err < 2 || (buf [0] == '#' && buf [1] == '!')) {
|
|
|
|
close(fd);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_gc_message(0x100, "Rejected #! script\n", 0);
|
2001-02-19 02:01:41 -08:00
|
|
|
return BAD_BYTECODE;
|
|
|
|
}
|
1996-07-24 05:58:12 -07:00
|
|
|
}
|
|
|
|
err = read_trailer(fd, trail);
|
2001-02-19 02:01:41 -08:00
|
|
|
if (err != 0) {
|
|
|
|
close(fd);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_gc_message(0x100, "Not a bytecode executable\n", 0);
|
2001-02-19 02:01:41 -08:00
|
|
|
return err;
|
|
|
|
}
|
1996-07-24 05:58:12 -07:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2000-03-05 11:18:50 -08:00
|
|
|
/* Read the section descriptors */
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
void caml_read_section_descriptors(int fd, struct exec_trailer *trail)
|
2000-03-05 11:18:50 -08:00
|
|
|
{
|
|
|
|
int toc_size, i;
|
|
|
|
|
|
|
|
toc_size = trail->num_sections * 8;
|
2003-12-31 06:20:40 -08:00
|
|
|
trail->section = caml_stat_alloc(toc_size);
|
2000-03-05 11:18:50 -08:00
|
|
|
lseek(fd, - (long) (TRAILER_SIZE + toc_size), SEEK_END);
|
|
|
|
if (read(fd, (char *) trail->section, toc_size) != toc_size)
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error("Fatal error: cannot read section table\n");
|
2000-03-05 11:18:50 -08:00
|
|
|
/* Fixup endianness of lengths */
|
|
|
|
for (i = 0; i < trail->num_sections; i++)
|
|
|
|
fixup_endianness_trailer(&(trail->section[i].len));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Position fd at the beginning of the section having the given name.
|
2001-02-19 04:29:00 -08:00
|
|
|
Return the length of the section data in bytes, or -1 if no section
|
|
|
|
found with that name. */
|
2000-03-05 11:18:50 -08:00
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
int32 caml_seek_optional_section(int fd, struct exec_trailer *trail, char *name)
|
2000-03-05 11:18:50 -08:00
|
|
|
{
|
|
|
|
long ofs;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ofs = TRAILER_SIZE + trail->num_sections * 8;
|
|
|
|
for (i = trail->num_sections - 1; i >= 0; i--) {
|
|
|
|
ofs += trail->section[i].len;
|
|
|
|
if (strncmp(trail->section[i].name, name, 4) == 0) {
|
|
|
|
lseek(fd, -ofs, SEEK_END);
|
|
|
|
return trail->section[i].len;
|
|
|
|
}
|
|
|
|
}
|
2001-02-19 04:29:00 -08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Position fd at the beginning of the section having the given name.
|
|
|
|
Return the length of the section data in bytes. */
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
int32 caml_seek_section(int fd, struct exec_trailer *trail, char *name)
|
2001-02-19 04:29:00 -08:00
|
|
|
{
|
2003-12-31 06:20:40 -08:00
|
|
|
int32 len = caml_seek_optional_section(fd, trail, name);
|
2010-01-22 04:48:24 -08:00
|
|
|
if (len == -1)
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error_arg("Fatal_error: section `%s' is missing\n", name);
|
2001-02-19 04:29:00 -08:00
|
|
|
return len;
|
2000-03-05 11:18:50 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
/* Read and return the contents of the section having the given name.
|
|
|
|
Add a terminating 0. Return NULL if no such section. */
|
1997-06-13 08:49:36 -07:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
static char * read_section(int fd, struct exec_trailer *trail, char *name)
|
1997-06-13 08:49:36 -07:00
|
|
|
{
|
2001-08-28 07:47:48 -07:00
|
|
|
int32 len;
|
|
|
|
char * data;
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
len = caml_seek_optional_section(fd, trail, name);
|
2001-08-28 07:47:48 -07:00
|
|
|
if (len == -1) return NULL;
|
2003-12-31 06:20:40 -08:00
|
|
|
data = caml_stat_alloc(len + 1);
|
2001-08-28 07:47:48 -07:00
|
|
|
if (read(fd, data, len) != len)
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error_arg("Fatal error: error reading section %s\n", name);
|
2001-08-28 07:47:48 -07:00
|
|
|
data[len] = 0;
|
|
|
|
return data;
|
1997-06-13 08:49:36 -07:00
|
|
|
}
|
|
|
|
|
1998-10-02 06:02:32 -07:00
|
|
|
/* Invocation of ocamlrun: 4 cases.
|
1996-07-24 05:58:12 -07:00
|
|
|
|
|
|
|
1. runtime + bytecode
|
1998-10-02 06:02:32 -07:00
|
|
|
user types: ocamlrun [options] bytecode args...
|
|
|
|
arguments: ocamlrun [options] bytecode args...
|
1996-07-24 05:58:12 -07:00
|
|
|
|
|
|
|
2. bytecode script
|
|
|
|
user types: bytecode args...
|
1998-10-02 06:02:32 -07:00
|
|
|
2a (kernel 1) arguments: ocamlrun ./bytecode args...
|
1996-07-24 05:58:12 -07:00
|
|
|
2b (kernel 2) arguments: bytecode bytecode args...
|
|
|
|
|
|
|
|
3. concatenated runtime and bytecode
|
|
|
|
user types: composite args...
|
|
|
|
arguments: composite args...
|
|
|
|
|
|
|
|
Algorithm:
|
|
|
|
1- If argument 0 is a valid byte-code file that does not start with #!,
|
|
|
|
then we are in case 3 and we pass the same command line to the
|
1998-10-02 06:02:32 -07:00
|
|
|
Objective Caml program.
|
1996-07-24 05:58:12 -07:00
|
|
|
2- In all other cases, we parse the command line as:
|
|
|
|
(whatever) [options] bytecode args...
|
|
|
|
and we strip "(whatever) [options]" from the command line.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
1997-05-13 07:45:38 -07:00
|
|
|
/* Configuration parameters and flags */
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
static uintnat percent_free_init = Percent_free_def;
|
|
|
|
static uintnat max_percent_free_init = Max_percent_free_def;
|
|
|
|
static uintnat minor_heap_init = Minor_heap_def;
|
|
|
|
static uintnat heap_chunk_init = Heap_chunk_def;
|
|
|
|
static uintnat heap_size_init = Init_heap_def;
|
|
|
|
static uintnat max_stack_init = Max_stack_def;
|
1996-11-07 02:57:59 -08:00
|
|
|
|
|
|
|
/* Parse options on the command line */
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static int parse_command_line(char **argv)
|
1996-11-07 02:57:59 -08:00
|
|
|
{
|
1998-04-14 07:48:34 -07:00
|
|
|
int i, j;
|
1996-11-07 02:57:59 -08:00
|
|
|
|
|
|
|
for(i = 1; argv[i] != NULL && argv[i][0] == '-'; i++) {
|
|
|
|
switch(argv[i][1]) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
case 't':
|
2004-04-22 02:54:43 -07:00
|
|
|
caml_trace_flag++;
|
1996-11-07 02:57:59 -08:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 'v':
|
2004-11-26 17:04:19 -08:00
|
|
|
if (!strcmp (argv[i], "-version")){
|
|
|
|
printf ("The Objective Caml runtime, version " OCAML_VERSION "\n");
|
|
|
|
exit (0);
|
2010-05-20 07:06:29 -07:00
|
|
|
}else if (!strcmp (argv[i], "-vnum")){
|
|
|
|
printf (OCAML_VERSION "\n");
|
|
|
|
exit (0);
|
2004-11-26 17:04:19 -08:00
|
|
|
}else{
|
|
|
|
caml_verb_gc = 0x001+0x004+0x008+0x010+0x020;
|
|
|
|
}
|
1996-11-07 02:57:59 -08:00
|
|
|
break;
|
1998-04-14 07:48:34 -07:00
|
|
|
case 'p':
|
2004-01-01 08:42:43 -08:00
|
|
|
for (j = 0; caml_names_of_builtin_cprim[j] != NULL; j++)
|
|
|
|
printf("%s\n", caml_names_of_builtin_cprim[j]);
|
1998-04-14 07:48:34 -07:00
|
|
|
exit(0);
|
|
|
|
break;
|
2001-02-19 04:29:00 -08:00
|
|
|
case 'b':
|
2008-03-14 06:47:24 -07:00
|
|
|
caml_record_backtrace(Val_true);
|
2001-02-19 04:29:00 -08:00
|
|
|
break;
|
2001-08-28 07:47:48 -07:00
|
|
|
case 'I':
|
|
|
|
if (argv[i + 1] != NULL) {
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_ext_table_add(&caml_shared_libs_path, argv[i + 1]);
|
2001-08-28 07:47:48 -07:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
break;
|
1996-11-07 02:57:59 -08:00
|
|
|
default:
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error_arg("Unknown option %s.\n", argv[i]);
|
1996-11-07 02:57:59 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2004-02-02 07:12:13 -08:00
|
|
|
/* Parse the OCAMLRUNPARAM variable */
|
1996-11-07 02:57:59 -08:00
|
|
|
/* The option letter for each runtime option is the first letter of the
|
1997-05-13 07:45:38 -07:00
|
|
|
last word of the ML name of the option (see [stdlib/gc.mli]).
|
|
|
|
Except for l (maximum stack size) and h (initial heap size).
|
|
|
|
*/
|
|
|
|
|
2002-06-05 05:26:08 -07:00
|
|
|
/* If you change these functions, see also their copy in asmrun/startup.c */
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
static void scanmult (char *opt, uintnat *var)
|
1997-05-13 07:45:38 -07:00
|
|
|
{
|
|
|
|
char mult = ' ';
|
2005-09-22 07:21:50 -07:00
|
|
|
int val;
|
|
|
|
sscanf (opt, "=%u%c", &val, &mult);
|
|
|
|
sscanf (opt, "=0x%x%c", &val, &mult);
|
|
|
|
switch (mult) {
|
|
|
|
case 'k': *var = (uintnat) val * 1024; break;
|
|
|
|
case 'M': *var = (uintnat) val * 1024 * 1024; break;
|
|
|
|
case 'G': *var = (uintnat) val * 1024 * 1024 * 1024; break;
|
|
|
|
default: *var = (uintnat) val; break;
|
|
|
|
}
|
1997-05-13 07:45:38 -07:00
|
|
|
}
|
1996-11-07 02:57:59 -08:00
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void parse_camlrunparam(void)
|
1996-11-07 02:57:59 -08:00
|
|
|
{
|
1999-11-09 07:39:42 -08:00
|
|
|
char *opt = getenv ("OCAMLRUNPARAM");
|
2008-12-03 10:09:09 -08:00
|
|
|
uintnat p;
|
1999-11-09 07:39:42 -08:00
|
|
|
|
|
|
|
if (opt == NULL) opt = getenv ("CAMLRUNPARAM");
|
|
|
|
|
1996-11-07 02:57:59 -08:00
|
|
|
if (opt != NULL){
|
|
|
|
while (*opt != '\0'){
|
|
|
|
switch (*opt++){
|
1997-05-19 08:42:21 -07:00
|
|
|
case 's': scanmult (opt, &minor_heap_init); break;
|
1997-05-13 07:45:38 -07:00
|
|
|
case 'i': scanmult (opt, &heap_chunk_init); break;
|
|
|
|
case 'h': scanmult (opt, &heap_size_init); break;
|
|
|
|
case 'l': scanmult (opt, &max_stack_init); break;
|
1997-05-21 08:28:15 -07:00
|
|
|
case 'o': scanmult (opt, &percent_free_init); break;
|
|
|
|
case 'O': scanmult (opt, &max_percent_free_init); break;
|
2003-12-29 14:15:02 -08:00
|
|
|
case 'v': scanmult (opt, &caml_verb_gc); break;
|
2008-03-14 06:47:24 -07:00
|
|
|
case 'b': caml_record_backtrace(Val_true); break;
|
2004-01-01 08:42:43 -08:00
|
|
|
case 'p': caml_parser_trace = 1; break;
|
2008-12-03 10:09:09 -08:00
|
|
|
case 'a': scanmult (opt, &p); caml_set_allocation_policy (p); break;
|
1996-11-07 02:57:59 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
extern void caml_init_ieee_floats (void);
|
1996-11-07 02:57:59 -08:00
|
|
|
|
2000-01-31 21:41:23 -08:00
|
|
|
#ifdef _WIN32
|
2001-04-10 04:14:33 -07:00
|
|
|
extern void caml_signal_thread(void * lpParam);
|
2000-01-31 21:41:23 -08:00
|
|
|
#endif
|
|
|
|
|
1996-11-07 02:57:59 -08:00
|
|
|
/* Main entry point when loading code from a file */
|
1996-07-24 05:58:12 -07:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport void caml_main(char **argv)
|
1996-07-24 05:58:12 -07:00
|
|
|
{
|
2000-03-05 11:18:50 -08:00
|
|
|
int fd, pos;
|
1996-07-24 05:58:12 -07:00
|
|
|
struct exec_trailer trail;
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * chan;
|
1999-02-14 08:48:25 -08:00
|
|
|
value res;
|
2001-08-28 07:47:48 -07:00
|
|
|
char * shared_lib_path, * shared_libs, * req_prims;
|
2002-02-11 05:51:40 -08:00
|
|
|
char * exe_name;
|
|
|
|
#ifdef __linux__
|
|
|
|
static char proc_self_exe[256];
|
|
|
|
#endif
|
1996-07-24 05:58:12 -07:00
|
|
|
|
|
|
|
/* Machine-dependent initialization of the floating-point hardware
|
|
|
|
so that it behaves as much as possible as specified in IEEE */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_init_ieee_floats();
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_init_custom_operations();
|
|
|
|
caml_ext_table_init(&caml_shared_libs_path, 8);
|
|
|
|
caml_external_raise = NULL;
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Determine options and position of bytecode file */
|
1997-06-13 08:49:36 -07:00
|
|
|
#ifdef DEBUG
|
2004-07-13 05:19:15 -07:00
|
|
|
caml_verb_gc = 0xBF;
|
1997-06-13 08:49:36 -07:00
|
|
|
#endif
|
1999-02-14 08:48:25 -08:00
|
|
|
parse_camlrunparam();
|
|
|
|
pos = 0;
|
2002-02-11 05:51:40 -08:00
|
|
|
exe_name = argv[0];
|
|
|
|
#ifdef __linux__
|
2004-01-01 08:42:43 -08:00
|
|
|
if (caml_executable_name(proc_self_exe, sizeof(proc_self_exe)) == 0)
|
2002-02-11 05:51:40 -08:00
|
|
|
exe_name = proc_self_exe;
|
|
|
|
#endif
|
2003-12-31 06:20:40 -08:00
|
|
|
fd = caml_attempt_open(&exe_name, &trail, 0);
|
1999-02-14 08:48:25 -08:00
|
|
|
if (fd < 0) {
|
|
|
|
pos = parse_command_line(argv);
|
|
|
|
if (argv[pos] == 0)
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error("No bytecode file specified.\n");
|
2002-02-11 05:51:40 -08:00
|
|
|
exe_name = argv[pos];
|
2003-12-31 06:20:40 -08:00
|
|
|
fd = caml_attempt_open(&exe_name, &trail, 1);
|
1999-02-14 08:48:25 -08:00
|
|
|
switch(fd) {
|
|
|
|
case FILE_NOT_FOUND:
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error_arg("Fatal error: cannot find file %s\n", argv[pos]);
|
1999-02-14 08:48:25 -08:00
|
|
|
break;
|
2001-02-19 02:01:41 -08:00
|
|
|
case BAD_BYTECODE:
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_fatal_error_arg(
|
1999-02-14 08:48:25 -08:00
|
|
|
"Fatal error: the file %s is not a bytecode executable file\n",
|
|
|
|
argv[pos]);
|
|
|
|
break;
|
1997-06-13 08:49:36 -07:00
|
|
|
}
|
1999-02-14 08:48:25 -08:00
|
|
|
}
|
2000-03-05 11:18:50 -08:00
|
|
|
/* Read the table of contents (section descriptors) */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_read_section_descriptors(fd, &trail);
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Initialize the abstract machine */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_init_gc (minor_heap_init, heap_size_init, heap_chunk_init,
|
|
|
|
percent_free_init, max_percent_free_init);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_init_stack (max_stack_init);
|
1999-02-14 08:48:25 -08:00
|
|
|
init_atoms();
|
|
|
|
/* Initialize the interpreter */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_interprete(NULL, 0);
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Initialize the debugger, if needed */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_debugger_init();
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Load the code */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_code_size = caml_seek_section(fd, &trail, "CODE");
|
|
|
|
caml_load_code(fd, caml_code_size);
|
2001-08-28 07:47:48 -07:00
|
|
|
/* Build the table of primitives */
|
|
|
|
shared_lib_path = read_section(fd, &trail, "DLPT");
|
|
|
|
shared_libs = read_section(fd, &trail, "DLLS");
|
|
|
|
req_prims = read_section(fd, &trail, "PRIM");
|
2003-12-29 14:15:02 -08:00
|
|
|
if (req_prims == NULL) caml_fatal_error("Fatal error: no PRIM section\n");
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_build_primitive_table(shared_lib_path, shared_libs, req_prims);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(shared_lib_path);
|
|
|
|
caml_stat_free(shared_libs);
|
|
|
|
caml_stat_free(req_prims);
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Load the globals */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_seek_section(fd, &trail, "DATA");
|
2003-12-29 14:15:02 -08:00
|
|
|
chan = caml_open_descriptor_in(fd);
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_global_data = caml_input_val(chan);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_close_channel(chan); /* this also closes fd */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(trail.section);
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Ensure that the globals are in the major heap. */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_oldify_one (caml_global_data, &caml_global_data);
|
|
|
|
caml_oldify_mopup ();
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Initialize system libraries */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_init_exceptions();
|
2003-12-16 10:09:44 -08:00
|
|
|
caml_sys_init(exe_name, argv + pos);
|
2000-01-31 21:41:23 -08:00
|
|
|
#ifdef _WIN32
|
2000-03-05 11:18:50 -08:00
|
|
|
/* Start a thread to handle signals */
|
2001-04-10 04:14:33 -07:00
|
|
|
if (getenv("CAMLSIGPIPE"))
|
2001-10-01 20:08:45 -07:00
|
|
|
_beginthread(caml_signal_thread, 4096, NULL);
|
2000-01-31 21:41:23 -08:00
|
|
|
#endif
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Execute the program */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_debugger(PROGRAM_START);
|
2004-01-02 11:23:29 -08:00
|
|
|
res = caml_interprete(caml_start_code, caml_code_size);
|
1999-02-14 08:48:25 -08:00
|
|
|
if (Is_exception_result(res)) {
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_exn_bucket = Extract_exception(res);
|
|
|
|
if (caml_debugger_in_use) {
|
|
|
|
caml_extern_sp = &caml_exn_bucket; /* The debugger needs the
|
|
|
|
exception value.*/
|
|
|
|
caml_debugger(UNCAUGHT_EXC);
|
2001-02-19 04:29:00 -08:00
|
|
|
}
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_fatal_uncaught_exception(caml_exn_bucket);
|
1996-07-24 05:58:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-11-07 02:57:59 -08:00
|
|
|
/* Main entry point when code is linked in as initialized data */
|
|
|
|
|
2004-02-22 07:07:51 -08:00
|
|
|
CAMLexport void caml_startup_code(
|
|
|
|
code_t code, asize_t code_size,
|
|
|
|
char *data, asize_t data_size,
|
|
|
|
char *section_table, asize_t section_table_size,
|
|
|
|
char **argv)
|
1996-11-07 02:57:59 -08:00
|
|
|
{
|
1999-02-14 08:48:25 -08:00
|
|
|
value res;
|
2010-01-20 08:26:46 -08:00
|
|
|
char* cds_file;
|
1996-11-07 02:57:59 -08:00
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_init_ieee_floats();
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_init_custom_operations();
|
1996-11-07 02:57:59 -08:00
|
|
|
#ifdef DEBUG
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_verb_gc = 63;
|
1996-11-07 02:57:59 -08:00
|
|
|
#endif
|
2010-01-20 08:26:46 -08:00
|
|
|
cds_file = getenv("CAML_DEBUG_FILE");
|
|
|
|
if (cds_file != NULL) {
|
|
|
|
caml_cds_file = caml_stat_alloc(strlen(cds_file) + 1);
|
|
|
|
strcpy(caml_cds_file, cds_file);
|
|
|
|
}
|
1996-11-07 02:57:59 -08:00
|
|
|
parse_camlrunparam();
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_external_raise = NULL;
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Initialize the abstract machine */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_init_gc (minor_heap_init, heap_size_init, heap_chunk_init,
|
|
|
|
percent_free_init, max_percent_free_init);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_init_stack (max_stack_init);
|
1999-02-14 08:48:25 -08:00
|
|
|
init_atoms();
|
|
|
|
/* Initialize the interpreter */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_interprete(NULL, 0);
|
2010-01-20 08:26:46 -08:00
|
|
|
/* Initialize the debugger, if needed */
|
|
|
|
caml_debugger_init();
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Load the code */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_start_code = code;
|
2010-01-20 08:26:46 -08:00
|
|
|
caml_code_size = code_size;
|
|
|
|
if (caml_debugger_in_use) {
|
|
|
|
int len, i;
|
|
|
|
len = code_size / sizeof(opcode_t);
|
|
|
|
caml_saved_code = (unsigned char *) caml_stat_alloc(len);
|
|
|
|
for (i = 0; i < len; i++) caml_saved_code[i] = caml_start_code[i];
|
|
|
|
}
|
1997-02-02 06:53:44 -08:00
|
|
|
#ifdef THREADED_CODE
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_thread_code(caml_start_code, code_size);
|
1997-02-02 06:53:44 -08:00
|
|
|
#endif
|
2001-08-28 07:47:48 -07:00
|
|
|
/* Use the builtin table of primitives */
|
2004-02-22 07:07:51 -08:00
|
|
|
caml_build_primitive_table_builtin();
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Load the globals */
|
2004-02-22 07:07:51 -08:00
|
|
|
caml_global_data = caml_input_value_from_block(data, data_size);
|
1999-02-14 08:48:25 -08:00
|
|
|
/* Ensure that the globals are in the major heap. */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_oldify_one (caml_global_data, &caml_global_data);
|
|
|
|
caml_oldify_mopup ();
|
2004-02-22 07:07:51 -08:00
|
|
|
/* Record the sections (for caml_get_section_table in meta.c) */
|
|
|
|
caml_section_table = section_table;
|
|
|
|
caml_section_table_size = section_table_size;
|
2010-01-20 08:26:46 -08:00
|
|
|
/* Initialize system libraries */
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_init_exceptions();
|
2003-12-16 10:09:44 -08:00
|
|
|
caml_sys_init("", argv);
|
2010-01-20 08:26:46 -08:00
|
|
|
/* Execute the program */
|
|
|
|
caml_debugger(PROGRAM_START);
|
|
|
|
res = caml_interprete(caml_start_code, caml_code_size);
|
|
|
|
if (Is_exception_result(res)) {
|
|
|
|
caml_exn_bucket = Extract_exception(res);
|
|
|
|
if (caml_debugger_in_use) {
|
|
|
|
caml_extern_sp = &caml_exn_bucket; /* The debugger needs the
|
|
|
|
exception value.*/
|
|
|
|
caml_debugger(UNCAUGHT_EXC);
|
|
|
|
}
|
|
|
|
caml_fatal_uncaught_exception(caml_exn_bucket);
|
|
|
|
}
|
1996-11-07 02:57:59 -08:00
|
|
|
}
|