/* |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
/* $Header: ldfcn.c,v 1.2.1.1 92/06/24 14:10:06 marker Exp $ */

/* Take a stab at ATT-free ldfcn interface */

#ifdef _SYSTYPE_BSD43
#include <stdio.h>
#endif
#include <assert.h>
#include <stdio.h>
#include "obj.h"
#include <ar.h>
#ifdef _BSD
#include <sys/file.h>
#else /* _SYSV || _SYSTYPE_SVR4 */
#include <fcntl.h>
#endif
#include "ldfcn.h"

#define LPOBJ(ldptr) ((ldptr)->obj)
#define LIOPTR(ldptr) ((ldptr)->ldfile.ioptr)
#define LSYMHEADER(ldptr) ((ldptr)->ldfile.pchdr)
#define LPHDR(ldptr) (LPOBJ(ldptr)->o_phdrr)
#define LFD(ldptr) ((ldptr)->arfd)
#define LTYPE(ldptr) ((ldptr)->ldfile.type)
#define LOFFSET(ldptr) ((ldptr)->aroffset)
extern char *malloc(), *calloc(), *realloc();
static elf32_LDFILE *nextfile(elf32_LDFILE *), *init_ldfile(elf32_LDFILE *);
#define MIPS_NSCNS 15
/*

LDFILE *ldaopen(char *filename, LDFILE *oldptr);

ldreadst(LDFILE *ldptr, int flags);

int ldclose(LDFILE *ldptr);

int ldaclose (LDFILE *ldptr);
*/

char	*_ldhead = NULL;
int ldlast_fnum_ = 0;

elf32_LDFILE *allocldptr() 
{
  static int count=0;
  elf32_LDFILE *ldptr;
  ldptr = (elf32_LDFILE *)calloc(1,sizeof(elf32_LDFILE));
  if (ldptr)
    ldptr->ldfile._fnum_ = ++count;
  return ldptr;
}

elf32_LDFILE *ldopen(char *filename, elf32_LDFILE *ldptr)
{
  int ifd,fd;
  char armagic[SARMAG];

  if (!vldldptr(ldptr)) {
    assert(ldptr = allocldptr());
    assert(LIOPTR(ldptr) = (FILE *)calloc(1,sizeof(FILE)));
    assert(LPOBJ(ldptr) = (pOBJ)calloc(1,cbOBJ));
  }
  else {
    ldfseek(ldptr,0,BEGINNING);
    return ldptr;
  }
/*    return nextfile(ldptr); */ /* OLD */

  fd = open(filename, O_RDONLY);
  if (fd < 0)
    return NULL;
  if (read(fd,armagic,SARMAG) != SARMAG) {
    close(fd);
    return NULL;
  }
  if (strncmp(armagic,ARMAG,SARMAG) == 0) {
    /* Archive file */
    LTYPE(ldptr) = ARTYPE;
    LFD(ldptr) = fd;
    LOFFSET(ldptr) = SARMAG;
    return nextfile(ldptr);
  }
  else {
    close(fd);
  }
  LFD(ldptr) = -1;

  if (obj_open(ldptr->obj, filename, OM_READ) != ldptr->obj) {
    if (LIOPTR(ldptr))
      free(LIOPTR(ldptr));
    if (LPOBJ(ldptr))
      free(LPOBJ(ldptr));
    free(ldptr);
    return NULL;
  }
  return init_ldfile(ldptr);
}

static elf32_LDFILE *nextfile(elf32_LDFILE *ldptr)
{
  ARHDR arhdr;
  off_t loc;
  unsigned long size;

  assert(LTYPE(ldptr) == ARTYPE);
  loc = lseek(LFD(ldptr),LOFFSET(ldptr),0);
  if (read(LFD(ldptr),(char *)&arhdr,sizeof(arhdr)) != sizeof(arhdr)) {
    return NULL;		/* end of archive */
  }
  strncpy(ldptr->archdr.ar_name,arhdr.ar_name,16);
  ldptr->archdr.ar_date = atol(arhdr.ar_date);
  ldptr->archdr.ar_uid = atol(arhdr.ar_uid);
  ldptr->archdr.ar_gid = atol(arhdr.ar_gid);
  ldptr->archdr.ar_mode = atol(arhdr.ar_mode);
  ldptr->archdr.ar_size = atol(arhdr.ar_size);
  ldptr->ldfile.offset = LOFFSET(ldptr);
  /* point to next member */
  LOFFSET(ldptr) = loc + sizeof(arhdr) + ((ldptr->archdr.ar_size+1)&~0x1);
  if (AR_ISSYMDEF(arhdr.ar_name) ||
      IS_ELF_AR_SYMTAB(arhdr.ar_name) ||
      IS_ELF_AR_STRTAB(arhdr.ar_name)) {
    return nextfile(ldptr);	/* skip symdef or elf symdef/strtab*/
  }
  assert(LPOBJ(ldptr) = obj_read_from_fd(LPOBJ(ldptr),LFD(ldptr),loc+sizeof(arhdr),ldptr->archdr.ar_size));
  return init_ldfile(ldptr);
}

static elf32_LDFILE *init_ldfile(elf32_LDFILE *ldptr)
{
  pCFDR pcfd;
  int ifd;
    /* offset,lastindex,type,fswap,fBigendian */

  LIOPTR(ldptr)->_cnt = LPOBJ(ldptr)->o_statb.st_size;
  LIOPTR(ldptr)->_base = 
    LIOPTR(ldptr)->_ptr = (unsigned char *)LPOBJ(ldptr)->o_praw;
  LIOPTR(ldptr)->_flag = _IOREAD;
  LIOPTR(ldptr)->_file = -1;
  
  if (LPOBJ(ldptr)->o_type == OT_MIPS_COFF) {
    ldptr->ldfile.header = * LPOBJ(ldptr)->o_pfilehdr;
  }
  else if (LPOBJ(ldptr)->o_type = OT_MIPS_ELF) {
    elf_spoof_coffhdrs(LPOBJ(ldptr),
		       LPOBJ(ldptr)->o_pfilehdr = &ldptr->ldfile.header,
		       LPOBJ(ldptr)->o_paouthdr = (struct aouthdr *)calloc(1,AOUTHSZ),
		       LPOBJ(ldptr)->o_pscnhdr = (struct scnhdr *)calloc(MIPS_NSCNS,SCNHSZ));
  }
  if (!LTYPE(ldptr))
    LTYPE(ldptr) = LPOBJ(ldptr)->o_pfilehdr->f_magic;
  ldptr->ldfile.fBigendian = gethostsex() == BIGENDIAN;
  /* fix bug 9736 */
  if (!obj_conflict_foreign(LPOBJ(ldptr)) && (hdr_symptr(LPOBJ(ldptr)))) {
    if (LPOBJ(ldptr)->o_phdrr->magic != magicSym) {
      LDERROR(init_ldfile, "non-mips symbol table %x\n", LPOBJ(ldptr)->o_phdrr->magic);
    }
    assert(LSYMHEADER(ldptr) = (pCHDRR) calloc(cbCHDRR,1));
    LSYMHEADER(ldptr)->pfd = LPOBJ(ldptr)->o_pfdr;
    LSYMHEADER(ldptr)->cfd = LSYMHEADER(ldptr)->cfdMax = 
      LPHDR(ldptr)->ifdMax;
    LSYMHEADER(ldptr)->psym = LPOBJ(ldptr)->o_psymr;
    LSYMHEADER(ldptr)->pext = LPOBJ(ldptr)->o_pextr;
    LSYMHEADER(ldptr)->cext = LSYMHEADER(ldptr)->cextMax = 
      LPHDR(ldptr)->iextMax;
    LSYMHEADER(ldptr)->pssext = LPOBJ(ldptr)->o_pssext;
    LSYMHEADER(ldptr)->cbssext = LSYMHEADER(ldptr)->cbssextMax = 
      LPHDR(ldptr)->issExtMax;
    LSYMHEADER(ldptr)->paux = LPOBJ(ldptr)->o_pauxu;
    LSYMHEADER(ldptr)->pss = LPOBJ(ldptr)->o_pss;
    LSYMHEADER(ldptr)->pdn = (pDNR) 0x1 /* TBD */ ;
    LSYMHEADER(ldptr)->cdn = LSYMHEADER(ldptr)->cdnMax = 
      LPHDR(ldptr)->idnMax;
    LSYMHEADER(ldptr)->popt = (pOPTR) 0x1 /* TBD */ ;
    LSYMHEADER(ldptr)->prfd = (pRFDT) LPOBJ(ldptr)->o_prfd;
    LSYMHEADER(ldptr)->ppd = LPOBJ(ldptr)->o_ppdr;
    LSYMHEADER(ldptr)->flags = 0 /* TBD */ ;
    LSYMHEADER(ldptr)->fswap = LPOBJ(ldptr)->o_target_swapped;
    LSYMHEADER(ldptr)->hdr = * LPHDR(ldptr);
    LSYMHEADER(ldptr)->fappend = 0; /* readonly */
    
    /* Expand line numbers */
#ifndef _DONT_EXPAND_LINE_NUMBERS
    if (LPHDR(ldptr)->ilineMax)
	assert(LSYMHEADER(ldptr)->pline = (pLINER)calloc(cbLINER,LPHDR(ldptr)->ilineMax));
#endif /* _DONT_EXPAND_LINE_NUMBERS */
    assert(LSYMHEADER(ldptr)->pcfd = (pCFDR)calloc(cbCFDR,LPHDR(ldptr)->ifdMax));
      for (ifd = 0; ifd < LPHDR(ldptr)->ifdMax; ifd++) {
	pcfd = &LSYMHEADER(ldptr)->pcfd[ifd];
	pcfd->pfd = LPOBJ(ldptr)->o_pfdr + ifd;
	if (pcfd->pfd->csym > 0) {
	  pcfd->psym = LPOBJ(ldptr)->o_psymr + pcfd->pfd->isymBase;
	  pcfd->freadin |= ST_PSYMS;
	}; /* if */
	if (pcfd->pfd->caux > 0) {
	  pcfd->paux = LPOBJ(ldptr)->o_pauxu + pcfd->pfd->iauxBase;
	  pcfd->freadin |= ST_PAUXS;
	}; /* if */
#if 0
	if (pcfd->pfd->copt > 0) {
	  pcfd->popt = LPHDR(ldptr)->popt + pcfd->pfd->ioptBase;
	  pcfd->freadin |= ST_POPTS;
	}; /* if */
#endif
	if (pcfd->pfd->crfd > 0) {
	  pcfd->prfd = (pRFDT) LPOBJ(ldptr)->o_prfd + pcfd->pfd->rfdBase;
	  pcfd->freadin |= ST_PRFDS;
	}; /* if */
	if (pcfd->pfd->cbSs > 0) {
	  pcfd->pss = LPOBJ(ldptr)->o_pss + pcfd->pfd->issBase;
	  pcfd->freadin |= ST_PSSS;
	}; /* if */
	if (pcfd->pfd->cpd > 0) {
	  pcfd->ppd = LPOBJ(ldptr)->o_ppdr + pcfd->pfd->ipdFirst;
	  pcfd->freadin |= ST_PPDS;
	}; /* if */
#ifndef _DONT_EXPAND_LINE_NUMBERS
	if (pcfd->pfd->cline > 0) {
	  pcfd->pline = (pLINER) LSYMHEADER(ldptr)->pline +
	    pcfd->pfd->ilineBase;
	  pcfd->freadin |= ST_PLINES;
	}; /* if */
#endif /* _DONT_EXPAND_LINE_NUMBERS */
      }
#ifndef _DONT_EXPAND_LINE_NUMBERS
    for (ifd = LPHDR(ldptr)->ifdMax - 1; ifd >= 0; ifd--) {
      pPDR		ppd;
      int		ipd;
      int		iline;
      int		ilineMax;	       /* last iline+1 for this proc */
      signed char	*pline;			/* pointer to packed lines */
      
      pcfd = &LSYMHEADER(ldptr)->pcfd[ifd];
      if (pcfd->pfd->cline == 0)
	continue;
      /* loop through each procedure moving its line entries to their
       *	proper position by unpacking it from the input buffer.
       *	An entry on disk is a byte long. The upper bits are the
       *	count (-1) and lower bits are the delta from the previous
       *	line number. If the delta is -8, then it is too big and we
       *	get it from the next 16 bits.
       */
      pline = (signed char *)LPOBJ(ldptr)->o_pline + pcfd->pfd->cbLineOffset;
      for (ipd = 0; ipd < pcfd->pfd->cpd; ipd ++) {
	int		count;		/* count part of packed line number */
	signed char	clinedelta;	/* delta part of packed line number */
	short	linedelta;	/* delta part of packed line number */
	int		ln;		/* current line number */
	int		ipd1;
	
	ppd = pcfd->ppd + ipd;
	
	if (ppd->iline == ilineNil || ppd->lnLow == -1 ||
	    ppd->lnHigh == -1)
	  continue;
	
	/* get stopping point for line number loop */
#if 0
	ipd1 = 1;
      next:
	if (ipd + ipd1 >= pcfd->pfd->cpd)
	  ilineMax = pcfd->pfd->cline;
	else if (ppd[ipd1].iline == -1 ||
		 (ppd[ipd1].lnHigh == -1 && ppd[ipd1].lnLow != -1)) {
	  ipd1++;		/* aent have .iline !=0, lnHigh==-1 */
	  goto next;
	} else
	  ilineMax = ppd[ipd1].iline;
#else
	ilineMax = pcfd->pfd->cline;
	for (ipd1 = 0;  ipd1 < pcfd->pfd->cpd;  ipd1++) {
	  /* Search for a procedure with a starting line entry
	   * that is greater than this procedure's, and smaller
	   * than the smallest one found so far.
	   */
	  if( (pcfd->ppd[ipd1].iline > ppd->iline) &&
	     (pcfd->ppd[ipd1].iline < ilineMax))
	    {
	      /* Found a better one */
	      ilineMax = pcfd->ppd[ipd1].iline;
	    }
	}
#endif
	ln = ppd->lnLow;
	for (iline = ppd->iline; iline < ilineMax;) {
	  count = (int)(*pline & 0x0f);
	  clinedelta = *pline++ >> 4;
	  if (clinedelta == -8) {
	    linedelta = (*pline << 8) | (pline[1] & 0xff);
	    pline += 2;
	    ln += linedelta;
	  } else {
	    ln += clinedelta;
	  } /* if */
	  for (; count >= 0; count --) {
	      if (iline < pcfd->pfd->cline)
		  pcfd->pline[iline++] = ln;
	  }
	} /* for */
      } /* for */
    } /* for */
#endif /* _DONT_EXPAND_LINE_NUMBERS */
  }
  return ldptr;
}

int ldclose(elf32_LDFILE *ldptr)
{
  if (vldldptr(ldptr) == FAILURE)
    return (SUCCESS);
  if (LTYPE(ldptr) == ARTYPE && nextfile(ldptr))
    return FAILURE;
  fclose(LIOPTR(ldptr));
  freeldptr(ldptr);
  return SUCCESS;		/* dispose of ldptr? */
}

nyi (char *name) 
{
  fprintf(stderr,"%s in not yet implemented...aborting\n",name);
  assert(0);
}

nop(char *name) { fprintf(stderr,"%s nop-ed out\n",name);}

void ldinitheaders() { nyi("ldinitheaders"); }

int ldreadst(elf32_LDFILE *ldptr, int flags) 
{
  st_setchdr(LSYMHEADER(ldptr));
  return SUCCESS; 
}

int ldfhread(elf32_LDFILE *ldptr, FILHDR *fh)
{
  *fh = *LPOBJ(ldptr)->o_pfilehdr;
  return SUCCESS;
}

int ldshread(elf32_LDFILE *ldptr, int which, SCNHDR *sh)
{
  *sh = LPOBJ(ldptr)->o_pscnhdr[which-1];
  return SUCCESS;
}

int vldldptr(elf32_LDFILE *ldptr)
{
  if (ldptr && LPOBJ(ldptr))
    return SUCCESS;
  else
    return FAILURE;
}

int freeldptr(elf32_LDFILE *ldptr)
{
  obj_close(LPOBJ(ldptr));
  LPOBJ(ldptr) = NULL;
  if (LSYMHEADER(ldptr)) {
      free(LSYMHEADER(ldptr)->pline);
      free(LSYMHEADER(ldptr)->pcfd);
      free(LSYMHEADER(ldptr));
  }
  free(ldptr);
  return SUCCESS;
}

int ldfseek(elf32_LDFILE *ldptr, int offset, int whence)
{
  switch (whence) {
  case BEGINNING:
    LIOPTR(ldptr)->_ptr = LIOPTR(ldptr)->_base + offset;
    break;
  case END:
    LIOPTR(ldptr)->_ptr = LIOPTR(ldptr)->_base + LIOPTR(ldptr)->_cnt - offset;
    break;
  case CURRENT:
    LIOPTR(ldptr)->_ptr += offset;
    break;
  default:
    fprintf(stderr,"Bad  offset in ldfseek\n");
    return ~OKFSEEK;
  }
  return OKFSEEK;
}

int ldfread(char *where,int size, int count, elf32_LDFILE *ldptr)
{
  memcpy(where,LIOPTR(ldptr)->_ptr,size*count);
  LIOPTR(ldptr)->_ptr += size * count;
  return count;
}

int ldlseek(elf32_LDFILE *ldptr, unsigned short sectnum)
{
  if (LPHDR(ldptr)->ilineMax && 
      (ldfseek(ldptr,LPHDR(ldptr)->cbLineOffset, BEGINNING) == OKFSEEK))
    return SUCCESS;
  return FAILURE;
}

int ldnlseek(elf32_LDFILE *ldptr, char *sectname)
{ return(ldlseek(ldptr,0)); }

int ldnrseek(elf32_LDFILE *ldptr, char *sectname)
{
  int i;
  
  for (i=0; i<LPOBJ(ldptr)->o_pfilehdr->f_nscns; i++) {
    if ((strcmp(sectname,LPOBJ(ldptr)->o_pscnhdr[i].s_name) == 0) &&
	(LPOBJ(ldptr)->o_pscnhdr[i].s_nreloc) &&
	(ldfseek(ldptr,LPOBJ(ldptr)->o_pscnhdr[i].s_relptr,BEGINNING)
	 == OKFSEEK))
      return SUCCESS;
  }
  return FAILURE;
}

int ldnsseek(elf32_LDFILE *ldptr, char *sectname)
{
  int i;
  
  for (i=0; i<LPOBJ(ldptr)->o_pfilehdr->f_nscns; i++) {
    if ((strncmp(sectname,LPOBJ(ldptr)->o_pscnhdr[i].s_name,
		 strlen(sectname) ) == 0) &&
	(LPOBJ(ldptr)->o_pscnhdr[i].s_scnptr) &&
	(ldfseek(ldptr,LPOBJ(ldptr)->o_pscnhdr[i].s_scnptr,BEGINNING)
	 == OKFSEEK))
      return SUCCESS;
  }
  return FAILURE;
}

int ldohseek(elf32_LDFILE *ldptr)
{				/* Need to handle spoof'ed coff */
  if ((LPOBJ(ldptr)->o_type == OT_MIPS_ELF)) {
    fprintf(stderr,"ldohseek is not supported\n");
    assert(0);
  }
  else {
    if ((LPOBJ(ldptr)->o_pfilehdr->f_opthdr) &&
	(ldfseek(ldptr,FILHSZ,BEGINNING) == OKFSEEK))
      return SUCCESS;
    return FAILURE;
  }
}

int ldrseek(elf32_LDFILE *ldptr, unsigned short sectnum)
{
  if (/*(LPOBJ(ldptr)->o_pscnhdr[sectnum-1].s_nreloc) &&*/
      (ldfseek(ldptr,LPOBJ(ldptr)->o_pscnhdr[sectnum-1].s_relptr,BEGINNING)
       == OKFSEEK))
    return SUCCESS;
  return FAILURE;
}

int ldsseek(elf32_LDFILE *ldptr, unsigned short sectnum)
{
  if ((LPOBJ(ldptr)->o_pscnhdr[sectnum-1].s_scnptr) &&
      (ldfseek(ldptr,LPOBJ(ldptr)->o_pscnhdr[sectnum-1].s_scnptr,BEGINNING)
       == OKFSEEK))
    return SUCCESS;
  return FAILURE;
}

int ldtbseek(elf32_LDFILE *ldptr)
{
  if (hdr_symptr(LPOBJ(ldptr)) &&
      (ldfseek(ldptr,LPHDR(ldptr)->cbSymOffset, BEGINNING) == OKFSEEK))
    return SUCCESS;
  return FAILURE;
}

int
ldnreloc(ldptr, psecthead)
     elf32_LDFILE *ldptr;
     SCNHDR *psecthead;
{
  if (LPOBJ(ldptr)->o_type == OT_MIPS_ELF) {
    return elf_nreloc(LPOBJ(ldptr),psecthead->s_flags);
  }
  else {
	RELOC relent;

	/* since the nreloc field can overflow if the section header flags
	 * have S_NRELOC_OVFL set then nreloc is the v_addr of the first
	 * relocation entry.
	 */
	 if (psecthead->s_relptr == 0)
	     return NULL;
	 if (psecthead->s_flags & S_NRELOC_OVFL) {

		if (ldnrseek(ldptr, psecthead->s_name) != SUCCESS) {
			LDERROR(ldnreloc, "cannot ldnrseek section %s\n", psecthead->s_name);
			return(-1);
		}

		if (FREAD((char *)&relent, RELSZ, 1, ldptr) != 1) {
			LDERROR(ldnreloc, "cannot FREAD relocation for %s\n", psecthead->s_name);
			return(-1);
		}
		if (ldptr->ldfile.fswap)
		    swap_reloc(&relent, 1, gethostsex());
		return relent.r_vaddr;
	 } else {
		return psecthead->s_nreloc;
	} /* if */
      }
} /* ldnreloc */

static void
hdrassign(oldptr, nldptr)
	elf32_LDFILE *oldptr;
	elf32_LDFILE *nldptr;
{
  LSYMHEADER(nldptr) = LSYMHEADER(oldptr);
}

/* Worry about obj reuse? Probably should */
elf32_LDFILE *
ldaopen(char *filename, elf32_LDFILE *oldptr)
{
  extern int vldldptr();
  elf32_LDFILE *nldptr;

  if (vldldptr(oldptr) == FAILURE || (nldptr = allocldptr()) == NULL)
    return (NULL);
  *nldptr = *oldptr;
  assert(LIOPTR(nldptr) = (FILE *)calloc(1,sizeof(FILE)));
  *LIOPTR(nldptr) = *LIOPTR(oldptr);
  return nldptr;
}

/* fix bug 10507 */
int
ldaclose(elf32_LDFILE *fileptr)
{
  if (vldldptr(fileptr) == FAILURE)
    return(NULL);
  free(LIOPTR(fileptr));
  free(fileptr);
  return (SUCCESS);
}

int ldahread(elf32_LDFILE *ldptr, ARCHDR *arhead)
{
  memcpy(arhead,&ldptr->archdr,ARCHSZ);
  return SUCCESS;
}

int ldohread(elf32_LDFILE *ldptr, AOUTHDR *aouthdr)
{
  /* Should take care of swapping! */
  if (LPOBJ(ldptr)->o_paouthdr) {
    *aouthdr = *LPOBJ(ldptr)->o_paouthdr;
    return SUCCESS;
  }
  return FAILURE;
}

int ldarsymread(elf32_LDFILE *ldptr, ARHDR *arhdr)
{
  off_t offset;
  int eof;

  if (LTYPE(ldptr) != ARTYPE)
    return FAILURE;
  lseek(LFD(ldptr),SARMAG,0);
  eof = 0;
  while (!eof) {
    if (read(LFD(ldptr),arhdr,sizeof(ARHDR)) != sizeof(ARHDR))
      eof = 1;
    else if (AR_ISSYMDEF(arhdr->ar_name)) {
      LPOBJ(ldptr)->o_statb.st_size = atol(arhdr->ar_size);
      assert(LPOBJ(ldptr)->o_praw = realloc(LPOBJ(ldptr)->o_praw,LPOBJ(ldptr)->o_statb.st_size));
      LIOPTR(ldptr)->_cnt = LPOBJ(ldptr)->o_statb.st_size;
      LIOPTR(ldptr)->_base = 
	LIOPTR(ldptr)->_ptr = (unsigned char *)LPOBJ(ldptr)->o_praw;
      LIOPTR(ldptr)->_flag = _IOREAD;
      LIOPTR(ldptr)->_file = -1;
      if (read(LFD(ldptr),LPOBJ(ldptr)->o_praw,LPOBJ(ldptr)->o_statb.st_size) !=
	  LPOBJ(ldptr)->o_statb.st_size)
	return FAILURE;
      return SUCCESS;
    }
    else {
      lseek(LFD(ldptr),atol(arhdr->ar_size),1); /* move forward */
    }
  }
  return FAILURE;
}

int ldnshread(elf32_LDFILE *ldptr, char *name, struct scnhdr *scnhdr)
{
  int i;
  for (i = 0; i<ldptr->ldfile.header.f_nscns; i++)
    /* fix bug 9956 -- assuming s_name is array[8] defined in scnhdr.h */
    if (strncmp(name,LPOBJ(ldptr)->o_pscnhdr[i].s_name,strlen(LPOBJ(ldptr)->o_pscnhdr[i].s_name)>8?8:strlen(LPOBJ(ldptr)->o_pscnhdr[i].s_name)) == 0) {
      *scnhdr = LPOBJ(ldptr)->o_pscnhdr[i];
      return SUCCESS;
    }
  return FAILURE;
}
