/*
 * Copyright (c) 1991-1993 by Xerox Corporation.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to copy this garbage collector for any purpose,
 * provided the above notices are retained on all copies.
 * Author: Bill Janssen
 * Modified by: Hans Boehm
 */

/*
 * This is incredibly OS specific code for tracking down data sections in
 * dynamic libraries.  There appears to be no way of doing this quickly
 * without groveling through undocumented data structures.  We would argue
 * that this is a bug in the design of the dlopen interface.  THIS CODE
 * MAY BREAK IN FUTURE OS RELEASES.  If this matters to you, don't hesitate
 * to let your vendor know ...
 */
#include "gc←private.h"
#ifdef DYNAMIC←LOADING
#if !(defined(M68K) && defined(SUNOS)) && !defined(SPARC)
 --> We only know how to find data segments of dynamic libraries under SunOS 4.X
#endif

#include <stdio.h>
#if defined SUNOS5
#   include <sys/elf.h>
#   include <dlfcn.h>
#   include <link.h>
#else
#   include <dlfcn.h>
#   include <link.h>
#   include <a.out.h>
  /* struct link←map field overrides */
#   define l←next	lm←next
#   define l←addr	lm←addr
#   define l←name	lm←name
# endif


#ifdef SUNOS5

static struct link←map *
GC←FirstDLOpenedLinkMap()
{
    extern Elf32←Dyn ←DYNAMIC;
    Elf32←Dyn *dp;
    struct r←debug *r;
    static struct link←map * cachedResult = 0;

    if( &←DYNAMIC == 0) {
        return(0);
    }
    if( cachedResult == 0 ) {
        int tag;
        for( dp = ((Elf32←Dyn *)(&←DYNAMIC)); (tag = dp->d←tag) != 0; dp++ ) {
            if( tag == DT←DEBUG ) {
                struct link←map *lm
                        = ((struct r←debug *)(dp->d←un.d←ptr))->r←map;
                if( lm != 0 ) cachedResult = lm->l←next; /* might be NIL */
                break;
            }
        }
    }
    return cachedResult;
}

# endif

# ifdef SUNOS4

static struct link←map *
GC←FirstDLOpenedLinkMap()
{
    extern struct link←dynamic ←DYNAMIC;

    if( &←DYNAMIC == 0) {
        return(0);
    }
    return(←DYNAMIC.ld←un.ld←1->ld←loaded);
}


# endif

/* Add dynamic library data sections to the root set.		*/
# if !defined(PCR) && defined(THREADS)
	--> fix mutual exclusion with dlopen
# endif
void GC←register←dynamic←libraries()
{
  struct link←map *lm = GC←FirstDLOpenedLinkMap();
  

  for (lm = GC←FirstDLOpenedLinkMap();
       lm != (struct link←map *) 0;  lm = lm->l←next)
    {
#     ifdef SUNOS4
	struct exec *e;
	 
        e = (struct exec *) lm->lm←addr;
        GC←add←roots←inner(
      		    ((char *) (N←DATOFF(*e) + lm->lm←addr)),
		    ((char *) (N←BSSADDR(*e) + e->a←bss + lm->lm←addr)));
#     endif
#     ifdef SUNOS5
	Elf32←Ehdr * e;
        Elf32←Phdr * p;
        unsigned long offset;
        char * start;
        register int i;
        
	e = (Elf32←Ehdr *) lm->l←addr;
        p = ((Elf32←Phdr *)(((char *)(e)) + e->e←phoff));
        offset = ((unsigned long)(lm->l←addr));
        for( i = 0; i < (int) e->e←phnum; ((i++),(p++)) ) {
          switch( p->p←type ) {
            case PT←LOAD:
              {
                if( !(p->p←flags & PF←W) ) break;
                start = ((char *)(p->p←vaddr)) + offset;
                GC←add←roots←inner(
                  start,
                  start + p->p←memsz
                );
              }
              break;
            default:
              break;
          }
	}
#     endif
    }
}

#else
void GC←register←dynamic←libraries(){}

int GC←no←dynamic←loading;
#endif