/* (c) Copyright by Anders Chrigstroem 1993, All rights reserved */
/* Permission is granted to use this source code and any executables
* created from this source code as part of the CD Gamedriver as long
* as it is not used in any way whatsoever for monetary gain. */
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif
#include "config.h"
#ifdef BINARIES /* Skip this entire file if BINARIES not defined */
#include "patchlevel.h"
#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "exec.h"
#define MAGIC "CDBIN"
#define align(x) ( ((x) + (sizeof(void*)-1) ) & ~(sizeof(void*)-1) )
extern int current_time;
extern int driver_mtime;
extern int comp_flag;
FILE *crfile(name)
char *name;
{
char *ptr, *dir = string_copy(name);
struct stat st;
ptr = dir;
for (ptr = strchr(ptr, '/'); ptr; ptr = strchr(ptr + 1, '/'))
{
*ptr = '\0';
if (stat(dir, &st) == -1)
{
if (mkdir(dir, 0774) == -1)
{
free(dir);
return (FILE *) 0;
}
}
else if ((st.st_mode & S_IFMT) != S_IFDIR)
{
if (unlink(dir) == -1 ||
mkdir(dir, 0774) == -1)
{
free(dir);
return (FILE *) 0;
}
}
*ptr = '/';
}
free(dir);
return fopen(name, "w");
}
static void
calculate_offsets(struct program *dest, struct program *prog)
{
int i, j;
for (i = 0; segm_desc[i].sections; i++)
{
struct section_desc *sec;
char *block;
if (segm_desc[i].ptr_offset != -1)
block = *(char **)(((char *)prog) + segm_desc[i].ptr_offset);
else
block = (char *)prog;
sec = segm_desc[i].sections;
for (j = 0; sec[j].section != -1; j++)
{
if (sec[j].ptr_offset != -1)
{
*(int *)(((char *)dest) + sec[j].ptr_offset) =
*(char **)(((char *)prog) + sec[j].ptr_offset) - block;
}
}
}
}
static void
restore_sections(struct program *dest, struct program *prog)
{
int i, j;
for (i = 0; segm_desc[i].sections; i++)
{
struct section_desc *sec;
char *block;
if (segm_desc[i].ptr_offset != -1)
block = *(char **)(((char *)prog) + segm_desc[i].ptr_offset);
else
block = (char *)dest;
if (segm_desc[i].swap_idx_offset != -1)
*(int *)(((char *)dest) + segm_desc[i].swap_idx_offset) = 0;
sec = segm_desc[i].sections;
for (j = 0; sec[j].section != -1; j++)
{
if (sec[j].ptr_offset != -1)
{
*(char **)(((char *)dest) + sec[j].ptr_offset) =
block + *(int *)(((char *)dest) + sec[j].ptr_offset);
}
}
}
}
int
save_binary(prog)
struct program *prog;
{
int i;
extern int driver_mtime;
char *binname;
extern struct object *master_ob;
extern char *add_slash(char *);
FILE *f;
int strsize = 0;
struct program pgm;
int strsize_tell;
struct svalue *ret;
if (master_ob)
{
push_malloced_string(add_slash(prog->name));
ret = apply_master_ob(M_VALID_SAVE_BINARY, 1);
if (!ret || ret->type != T_NUMBER || !ret->u.number)
{
if (comp_flag)
fprintf(stderr, "BIN Save for %s not allowed!\n",
prog->name);
return 0;
}
}
binname = (char *)xalloc(strlen(BINARIES) +
strlen(prog->name) + 1);
sprintf(binname, "%s%s", BINARIES, prog->name);
if ((f = crfile(binname)) == NULL)
{
if (comp_flag)
fprintf(stderr, "BIN Can't create file %s!\n",
binname);
free(binname);
return 0;
}
fwrite(MAGIC, sizeof(char), strlen(MAGIC), f);
fwrite((char *)&driver_mtime, sizeof(driver_mtime), 1, f);
strsize_tell = ftell(f);
fwrite((char *)&strsize, sizeof(strsize), 1, f);
load_lineno_from_swap(prog);
/* Write out the different segments of the program */
fwrite((char *)prog, prog->total_size, 1, f);
fwrite((char *)prog->program, prog->exec_size, 1, f);
fwrite((char *)prog->line_numbers, prog->debug_size, 1, f);
/* Write the inherit names, and the names of the
inherited programs to the strtab */
for (i = 0; i < prog->num_inherited; i++)
{
char *str;
struct program *iprog = prog->inherit[i].prog;
char buff[100];
str = iprog->name;
fwrite(str, strlen(str) + 1, 1, f);
strsize += strlen(str) + 1;
sprintf(buff, "%d", iprog->mod_time);
fwrite(buff, strlen(buff) + 1, 1, f);
strsize += strlen(buff) + 1;
str = prog->inherit[i].name;
fwrite(str, strlen(str) + 1, 1, f);
strsize += strlen(str) + 1;
}
/* Write the function names to the strtab */
for (i = 0; i < prog->num_functions; i++)
{
char *str = prog->functions[i].name;
fwrite(str, strlen(str) + 1, 1, f);
strsize += strlen(str) + 1;
}
/* Write the variable names to the strtab */
for (i = 0; i < prog->num_variables; i++)
{
char *str = prog->variable_names[i].name;
fwrite(str, strlen(str) + 1, 1, f);
strsize += strlen(str) + 1;
}
if (!strsize)
{
fwrite((char *)&strsize, sizeof(strsize), 1, f);
strsize = sizeof(strsize);
}
/* Write the size of the extra stringtable */
fseek(f, strsize_tell, SEEK_SET);
fwrite((char *)&strsize, sizeof(strsize), 1, f);
/* Write a new program header with offsets instead of
pointers for the sections */
pgm = *prog;
calculate_offsets(&pgm, prog);
fwrite((char *)&pgm, sizeof(pgm), 1, f);
swap_lineno(prog);
fclose(f);
if (comp_flag)
fprintf(stderr, "BIN %s saved!\n",
binname);
free(binname);
return pgm.mod_time;
}
int load_binary(FILE *f, char *lname)
{
extern int current_id_number;
struct program pgm;
struct program *progp;
extern struct program *prog;
extern char *inherit_file;
extern driver_mtime;
int comp_driver_mtime;
extern int total_lines; /* not used */
char buf[100];
char *strtab, *strptr;
int strsize;
int i;
extern int total_prog_block_size, total_program_size,
total_num_prog_blocks;
int pgm_seek;
extern void hash_func (int size, struct function *from,
struct function_hash *to);
if (inherit_file)
{
free(inherit_file);
inherit_file = (char *)0;
}
/* Is the file compatible with the current driver? */
fread(buf, sizeof(char), strlen(MAGIC), f);
fread((char *)&comp_driver_mtime, sizeof(comp_driver_mtime), 1, f);
if (strncmp(buf, MAGIC, strlen(MAGIC)) ||
comp_driver_mtime != driver_mtime)
{
fclose(f);
if (comp_flag)
fprintf(stderr, "BIN Wrong magic for %s!\n",
lname);
prog = 0;
return -1;
}
/* Read strtab size and program header */
fread((char *)&strsize, sizeof(strsize), 1, f);
if (!strsize)
{
prog = 0;
return -1;
}
pgm_seek = ftell(f);
fread((char *)&pgm, sizeof(pgm), 1 ,f);
/* Allocate segments */
progp = (struct program *)xalloc(pgm.total_size);
pgm.program = xalloc(pgm.exec_size);
pgm.line_numbers = xalloc(pgm.debug_size);
/* Read segments */
fseek(f, pgm_seek, SEEK_SET);
fread((char *)progp, pgm.total_size, 1, f);
fread(pgm.program, pgm.exec_size, 1, f);
fread(pgm.line_numbers, pgm.debug_size, 1, f);
/* Calculate pointers for sections from the offsets in the header */
restore_sections(progp, &pgm);
/* Read the extra strtab */
strptr = strtab = xalloc(strsize);
fread(strtab, strsize, 1, f);
/* Done reading from the file! */
fclose(f);
/* Now comes an check of the ages of all INCLUDED files: */
if (progp->sizeof_include_files)
{
struct stat stb;
int age;
char *t, *s;
t = progp->include_files;
while(t < progp->include_files + progp->sizeof_include_files)
{
age = atoi(t);
s = strchr(t, ':');
if (!s)
{
if (comp_flag)
fprintf(stderr,
"BIN Can not separate age & iname %s->%s!\n",
lname, t);
/* Free allocated memory */
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
prog = 0;
return -1;
}
else
t = s + 1;
if (stat(t, &stb) == -1)
{
if (comp_flag)
fprintf(stderr,
"BIN Included file not found (%s->%s)\n",
lname, t);
/* Free allocated memory */
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
prog = 0;
return -1;
}
if (stb.st_mtime != age)
{
if (comp_flag)
fprintf(stderr,"BIN Included file changed (%s->%s)\n",
lname, t);
/* Free allocated memory */
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
prog = 0;
return -1;
}
t += strlen(t) + 1;
}
}
/* Find the inherited programs */
for (i = 0; i < progp->num_inherited - 1; i++)
{
extern struct object *find_object2(char *);
struct object *ob;
int mod_time;
ob = find_object2(strptr);
if (!ob)
{
inherit_file = string_copy(strptr);
for (i--; i >= 0; i--)
free_string(progp->inherit[i].name);
if (comp_flag)
fprintf(stderr,"BIN Inherited file not loaded (%s->%s)\n",
lname, inherit_file);
/* Free allocated memory */
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
prog = 0;
return 0;
}
strptr += strlen(strptr) + 1;
mod_time = atoi(strptr);
if (mod_time != ob->prog->mod_time)
{
/* Free allocated memory */
for (i--; i >= 0; i--)
free_string(progp->inherit[i].name);
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
if (comp_flag)
fprintf(stderr,"BIN Inherited file changed (%s(%d)->%s(%d))\n",
lname, mod_time, ob->prog->name, mod_time);
prog = 0;
return -1;
}
strptr += strlen(strptr) + 1;
progp->inherit[i].prog = ob->prog;
progp->inherit[i].name = make_shared_string(strptr);
strptr += strlen(strptr) + 1;
}
/* Fix the inherit self */
/* Check that the name is correct */
if (strcmp(lname, strptr))
{
if (comp_flag)
fprintf(stderr,"BIN Wrong file name (%s->%s)\n",
lname, strptr);
/* Free allocated memory */
for (i--; i >= 0; i--)
free_string(progp->inherit[i].name);
free(pgm.program);
free((char *)pgm.line_numbers);
free((char *)progp);
free(strtab);
prog = 0;
return -1;
}
progp->name = string_copy(strptr);
strptr += strlen(strptr) + 1;
strptr += strlen(strptr) + 1; /* skip mod_time */
progp->inherit[i].name = make_shared_string(strptr);
strptr += strlen(strptr) + 1;
progp->inherit[i].prog = progp;
/* Read the function names */
for (i = 0; i < progp->num_functions; i++)
{
progp->functions[i].name =
make_shared_string(strptr);
strptr += strlen(strptr) + 1;
#ifdef PROFILE_FUNS
progp->functions[i].num_calls = 0;
progp->functions[i].time_spent = 0;
#ifdef SOLARIS
progp->functions[i].ticks_call = 0;
#else
progp->functions[i].stime_call = 0;
progp->functions[i].utime_call = 0;
#endif
#endif
}
/* Read the variable name */
for (i = 0; i < progp->num_variables; i++)
{
progp->variable_names[i].name =
make_shared_string(strptr);
strptr += strlen(strptr) + 1;
}
free(strtab);
/* Done! */
hash_func(progp->num_functions, progp->functions, progp->func_hash);
progp->ref = 0;
progp->swap_num = 0;
progp->id_number = current_id_number++;
progp->cpu = 0;
progp->swap_lineno_index = 0;
progp->load_time = current_time;
for(i = 0; i < (int)progp->num_inherited; i++)
reference_prog(progp->inherit[i].prog, "inheritance");
total_prog_block_size += progp->total_size;
total_program_size += progp->exec_size;
total_num_prog_blocks += 1;
register_program(progp);
progp->load_time = current_time;
swap_lineno(progp);
prog = progp;
return 0;
}
#endif