ftp.nice.ch/pub/next/developer/languages/lisp/AKCL.1.599.s.tar.gz#/akcl-1-599/unixport/mach_rsym.c

This is mach_rsym.c in view mode; [Download] [Up]

#define MACH_O
#define A_OUT
#include "config.h"
#include "ext_sym.h"

#include <stdio.h>
#include <ar.h>
#include <sys/types.h>
#include <sys/file.h>

#if !defined(A_OUT) && !defined(MACH_O)
#define A_OUT
#endif

#ifdef MACH_O
#ifndef A_OUT
#include <nlist.h>
#ifndef N_TEXT
#define N_TEXT 4
#define N_DATA 6
#define N_BSS 8
#endif
#ifndef N_FN
#define N_FN 15
#endif
#endif
#include <sys/loader.h>
#endif

/* Always use the GNU version of debugging symbol type codes, if possible.  */
#include "stab.h"

/* Struct or union for header of object file.  */

#ifdef USG
#include <string.h>
/* You might need to compile with -I/usr/include/sys if your fcntl.h
   isn't in /usr/include (which is where it should be according to POSIX).  */
#include <fcntl.h>
#else
#include <strings.h>
#endif

/* Alloca definitions and includes...  */

/* If compiled with GNU C, use the built-in alloca */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
/* If on a sun 4, make sure to include the right definition.  */
#if defined(sun) && defined(sparc)
#include "alloca.h"
#else
char *alloca ();
#endif
#endif

char *malloc (), *realloc ();

char *xmalloc (), *xrealloc ();

/* Special global symbol types understood by GNU LD.  */

/* The following type indicates the definition of a symbol as being
   an indirect reference to another symbol.  The other symbol
   appears as an undefined reference, immediately following this symbol.

   Indirection is asymmetrical.  The other symbol's value will be used
   to satisfy requests for the indirect symbol, but not vice versa.
   If the other symbol does not have a definition, libraries will
   be searched to find a definition.  */
#ifndef N_INDR
#define N_INDR 0xa
#endif

/* Warning message symbol.  The name of this symbol will be printed if
   any symbols from its file are required by the linker.  */
#ifndef N_WARNING
#define N_WARNING 0x1e
#endif
   

/* The following symbols refer to set elements.
   All the N_SET[ATDB] symbols with the same name form one set.
   Space is allocated for the set in the text section, and each set
   element's value is stored into one word of the space.
   The first word of the space is the length of the set (number of elements).

   The address of the set is made into an N_SETV symbol
   whose name is the same as the name of the set.
   This symbol acts like a N_DATA global symbol
   in that it can satisfy undefined external references.  */

#ifndef N_SETA
#define	N_SETA	0x14		/* Absolute set element symbol */
#endif				/* This is input to LD, in a .o file.  */

#ifndef N_SETT
#define	N_SETT	0x16		/* Text set element symbol */
#endif				/* This is input to LD, in a .o file.  */

#ifndef N_SETD
#define	N_SETD	0x18		/* Data set element symbol */
#endif				/* This is input to LD, in a .o file.  */

#ifndef N_SETB
#define	N_SETB	0x1A		/* Bss set element symbol */
#endif				/* This is input to LD, in a .o file.  */

/* Macros dealing with the set element symbols defined in a.out.h */
#define	SET_ELEMENT_P(x)	((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
#define TYPE_OF_SET_ELEMENT(x)	((x)-N_SETA+N_ABS)

#ifndef N_SETV
#define N_SETV	0x1C		/* Pointer to set vector in text area.  */
#endif				/* This is output from LD.  */

#ifndef __GNU_STAB__

/* Line number for the data section.  This is to be used to describe
   the source location of a variable declaration.  */
#ifndef N_DSLINE
#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
#endif

/* Line number for the bss section.  This is to be used to describe
   the source location of a variable declaration.  */
#ifndef N_BSLINE
#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
#endif

#endif /* not __GNU_STAB__ */

char *program_name;
char *output_name;

#ifdef MACH_O
/* Section ordinals for N_SECT references.  */
int text_section;
int data_section;
int bss_section;
#endif

/* The __.SYMDEF member of an archive has the following format:
   1) A longword saying the size of the symdef data that follows
   2) Zero or more  struct symdef  filling that many bytes
   3) A longword saying how many bytes of strings follow
   4) That many bytes of string data.
*/

struct symdef
  {
    long stringoffset;	/* Offset of this symbol's name in the string data */
    long offset;	/* Offset in the archive of the header-data for the member that
			   defines this symbol.  */
  };

/* Create a table of debugging stab-codes and corresponding names.  */
#ifdef __GNU_STAB__
#define __define_stab(NAME, CODE, STRING) {NAME, STRING},
struct {enum __stab_debug_code code; char *string;} stab_names[]
  = {
#include "stab.def"
    };
#undef __define_stab
#endif

char *concat ();
void do_one_file ();
void do_one_rel_file ();
void fatal ();
void perror_name ();
void print_file_name ();

void
main (argc, argv)
     char **argv;
     int argc;
{
  program_name = argv[0];

  if (argc != 3) {
    fprintf (stderr, "Usage: %s infile outfile \n", program_name);
    exit (1);
  }

  output_name = argv[2];
  do_one_file (argv[1]);

  exit (0);
}


void
do_one_file (name)
     char *name;
{
  int desc;

  desc = open (name, O_RDONLY, 0);

  if (desc < 0)
    {
      perror_name (name);
      return;
    }

  do_one_rel_file (desc, 0);

  close (desc);
}

/* Read a file's header and fill in various pieces of information.
   Return 0 on failure.  */

int
read_header_info (desc, offset, syms_offset, syms_size, strs_offset, strs_size)
     int desc;
     long int offset;
     long int *syms_offset;
     unsigned int *syms_size;
     long int *strs_offset;
     unsigned int *strs_size;
{
  int len;

#ifdef A_OUT
  {
    struct exec hdr;

    lseek (desc, offset, 0);
#ifdef HEADER_SEEK_FD
    /* Skip the headers that encapsulate our data in some other format
       such as COFF.  */
    HEADER_SEEK_FD (desc);
#endif
    len = read (desc, (char *) &hdr, sizeof (struct exec));
    if (len == sizeof (struct exec) && !N_BADMAG (hdr))
      {
	*syms_offset = N_SYMOFF(hdr);
	*syms_size = hdr.a_syms;
	*strs_offset = N_STROFF(hdr);
	lseek(desc, N_STROFF(hdr) + offset, 0);
	if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
	  {
	    fprintf(stderr, "cannot read string table size\n");
	    return 0;
	  }
	return 1;
      }
  }
#endif

#ifdef MACH_O
  {
    struct mach_header mach_header;
    char *hdrbuf;
    struct load_command *load_command;
    struct segment_command *segment_command;
    struct section *section;
    struct symtab_command *symtab_command;
    int symtab_seen;
    int len, cmd, seg, ordinal;

    symtab_seen = 0;

    lseek (desc, offset, 0);
    len = read (desc, (char *) &mach_header, sizeof (struct mach_header));
    if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC)
      {
	hdrbuf = xmalloc (mach_header.sizeofcmds);
	len = read (desc, hdrbuf, mach_header.sizeofcmds);
	if (len != mach_header.sizeofcmds)
	  {
	    fprintf (stderr, "failure reading Mach-O load commands\n");
	    return 0;
	  }
	load_command = (struct load_command *) hdrbuf;
	ordinal = 1;
	for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
	  {
	    switch (load_command->cmd)
	      {
	      case LC_SEGMENT:
		segment_command = (struct segment_command *) load_command;
		section = (struct section *) ((char *) (segment_command + 1));
		for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal)
		  {
		    if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname))
		      text_section = ordinal;
		    else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname))
		      data_section = ordinal;
		    else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname))
		      bss_section = ordinal;
		  }
		break;
	      case LC_SYMTAB:
		if (symtab_seen)
		  fprintf (stderr, "more than one LC_SYMTAB\n");
		else
		  {
		    symtab_seen = 1;
		    symtab_command = (struct symtab_command *) load_command;
		    *syms_offset = symtab_command->symoff;
		    *syms_size = symtab_command->nsyms * sizeof (struct nlist);
		    *strs_offset = symtab_command->stroff;
		    *strs_size = symtab_command->strsize;
		  }
		break;
	      }
	    load_command = (struct load_command *)
	      ((char *) load_command + load_command->cmdsize);
	  }
	free (hdrbuf);
	return 1;
      }
  }
#endif

  return 0;
}

void print_symbols ();
void print_one_symbol ();
void read_header ();

void
do_one_rel_file (desc, offset)
     int desc;
     int offset;
{
  struct nlist *symbols_and_strings;
  int symcount;
  int totalsize;
  char *strings;
  long int syms_offset, strs_offset;
  unsigned int syms_size, strs_size;

  if (!read_header_info (desc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
    {
      fprintf (stderr, "malformed input (not a rel file or archive)\n");
      return;
    }

  /* Number of symbol entries in the file.  */
  symcount = syms_size / sizeof (struct nlist);

  totalsize = strs_size + syms_size;

  /* Allocate space for symbol entries and string table.  */
  symbols_and_strings = (struct nlist *) xmalloc (totalsize);
  strings = (char *) symbols_and_strings + syms_size;

  /* Read them both in.  */
  lseek (desc, syms_offset + offset, 0);
  if (syms_size != read (desc, (char *) symbols_and_strings, syms_size))
    {
      fprintf (stderr, "premature end of file in symbols\n");
      return;
    }
  lseek (desc, strs_offset + offset, 0);
  if (strs_size != read (desc, (char *) strings, strs_size))
    {
      fprintf (stderr, "premature end of file in strings\n");
      return;
    }

  /* Modify each symbol entry to point directly at the symbol name.
     This is so the sort routine does not need to be passed
     the value of `strings' separately.  */

  {
    struct nlist *p = symbols_and_strings;
    struct nlist *end = symbols_and_strings + symcount;

    for (; p < end; p++)
      {
	/* A zero index means there is no string.  */
	if (p->n_un.n_strx != 0)
	  {
	    if (p->n_un.n_strx > 0 && p->n_un.n_strx < strs_size)
	      p->n_un.n_name = strings + p->n_un.n_strx;
	    else
	      {
		fprintf (stderr, "invalid string table offset\n");
		return;
	      }
	  }
      }
  }

  /* Print the symbols in the order they are now in.  */

  print_symbols (symbols_and_strings, symcount);

  free (symbols_and_strings);
}

struct lsymbol_table tab;

void
print_symbols (syms, symcount)
     struct nlist *syms;
     int symcount;
{
  int i;
  FILE *symout = fopen(output_name, "w");

  if (!symout) {
    perror_name (output_name);
    exit(1);
  }
  tab.n_symbols = tab.tot_leng = 0;
  fseek (symout, sizeof(struct lsymbol_table), 0);
  for (i = 0; i < symcount; i++)
    print_one_symbol (&syms[i], symout);
  fseek (symout, 0, 0);
  fwrite (&tab, sizeof(tab), 1, symout);
  fclose(symout);
}

void
print_one_symbol (sym, symout)
     struct nlist *sym;
     FILE *symout;
{
  char *name;

  if (EXT_and_TEXT_BSS_DAT(sym) && (sym->n_value)) {
    name = sym->n_un.n_name;
    tab.n_symbols++;
    fwrite(&(sym->n_value), sizeof(int), 1, symout);
    while (tab.tot_leng++, *name)
      putc (*name++, symout);
    putc (0, symout);
  }

}

/* Report a fatal error.
   STRING is a printf format string and ARG is one arg for it.  */

void
fatal (string, arg)
     char *string, *arg;
{
  fprintf (stderr, "%s: ", program_name);
  fprintf (stderr, string, arg);
  fprintf (stderr, "\n");
  exit (1);
}

/* Report a fatal error using the message for the last failed system call,
   followed by the string NAME.  */

void
perror_name (name)
     char *name;
{
  extern int errno, sys_nerr;
  extern char *sys_errlist[];
  char *s;

  if (errno < sys_nerr)
    s = concat ("", sys_errlist[errno], " for %s");
  else
    s = "cannot open %s";
  fprintf (stderr, s, name);
}

/* Like malloc but get fatal error if memory is exhausted.  */

char *
xmalloc (size)
     unsigned size;
{
  char *result = malloc (size);

  if (!result)
    fatal ("virtual memory exhausted", 0);
  return result;
}

/* Like realloc but get fatal error if out of memory.  */

char *
xrealloc (p, size)
     char *p;
     unsigned size;
{
  char *result = realloc(p, size);

  if (!result)
    fatal ("virtual memory exhausted", 0);
  return result;
}

/* Return a newly-allocated string
   whose contents concatenate those of S1, S2, S3.  */

char *
concat (s1, s2, s3)
     char *s1, *s2, *s3;
{
  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  char *result = (char *) xmalloc (len1 + len2 + len3 + 1);

  strcpy (result, s1);
  strcpy (result + len1, s2);
  strcpy (result + len1 + len2, s3);
  result[len1 + len2 + len3] = 0;

  return result;
}

#ifdef USG

getpagesize ()
{
  return (4096);
}

#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.