/* begincopyright Copyright (c) 1988 Xerox Corporation. All rights reserved. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to: PCR Coordinator Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA 94304 endcopyright */ /* * IncrementalLoad.h * * Incremental loading into PCR. * * Demers April 9, 1990 8:35:27 am PDT */ /* * * This interface provides dynamic loading of code into a PCR world, * relocating the code, resolving external references, allocating * common areas, etc. * * Multiple object file formats are supported. New object file readers * may register themselves at any time -- see IncrementalLoadPrivate.h * for details. * * The incremental loader maintains a primitive *load state* consisting * of a *file table* and a *symbol table*. * * The file table holds information about individual files that have * have been loaded: file name and type, address(es) where the file * was loaded, etc. Each file is loaded in up to 5 segments: * * - text, data, bss: like standard Unix. * - common: like bss, but allocated separately when common symbols get * defined. * - patch: area in which debugger can store short code sequences (e.g. * for breakpoints); the architecture may require this to be "near" * the text segment. * * all these segment addresses appear in file table entries. * * The symbol table holds information about all global symbols and all * (local or global) procedure/label symbols (local procedure info is * helpful for debugging and necessary for stack unwinding on certain * processors). Each symbol entry points to the file entry for the * containing file. Symbols are accessible either by name or by value. * * The data structures are designed to appear consistent at all times, * so a debugger can freeze the PCR world and examine the load state. * Normal clients (those that don't freeze the world and examine it * from outside) need to follow a locking discipline: * * call XR←LockIncrementalLoadState * examine or update the load state * call XR←UnlockIncrementalLoadState * * The incremental loader maintains the invariant that there are * no unresolved external references in the loaded code. This * could make it impossible to load several mutually-dependent * object files, so the invariant is enforced only at *commit points*. * * To load one or more object files, a client peforms the following * sequence: * * call XR←LockIncrementalLoadState * call XR←ILLoadFile to load first file * . . . * call XR←ILLoadFile to load last file * call XR←CommitIncrementalLoad * call XR←UnlockIncrementalLoadState * * The call to XR←CommitIncrementalLoad will fail if there are any * undefined symbols. If it fails, the client can either give up: * * call XR←AbortIncrementalLoad * call XR←UnlockIncrementalLoadState * * or try to fix things by doing a library search: * * while( calling XR←ILEnumerateUndefinedSyms produces symbols ) { * find a library module that defines an undefined symbol * call XR←ILLoadFile to load it * } * call XR←CommitIncrementalLoad -- will succeed! * call XR←UnlockIncrementalLoadState * */ #ifndef ←XR←INCREMENTAL←LOAD← #define ←XR←INCREMENTAL←LOAD← 1 #include <sys/types.h> #include <xr/BasicTypes.h> /* * Error result returned from many IL calls. * * a NIL result means the call succeeded ... */ typedef struct XR←ILErrorRep { bool ile←fatal; /* all incr loads since last commit are aborted */ int ile←code; /* > 0 ==> value from Errno.h */ char *ile←msg; /* human-readable */ } * XR←ILError; /* * Incremental Load State Locking * * Data is guaranteed to be consistent only while lock is held. */ extern XR←ILError XR←LockIncrementalLoadState(/* bool wait */); /* Try to acquire lock on load state. The `wait' parameter says whether to block until it's available. Waiting is abortable. Result.ile←code may be ETIMEDOUT or XR←EABORTED. A successful call must be followed (eventually) by a call to UnlockIncrementalLoadState. */ extern XR←ILError XR←UnlockIncrementalLoadState(); /* Release lock on load state. Result.ile←code may be EINVAL if lock is not held. */ /* * Incremental Load File record */ typedef struct XR←ILFileEntryRep { /* incremental load info */ unsigned ilfe←seqNum; bool ilfe←commitPoint; /* file info */ char * ilfe←fName; unsigned ilfe←fOffset; unsigned ilfe←fMagic; size←t ilfe←fSize; time←t ilfe←fMTime; /* version stamp (optionally supplied by installation proc) */ unsigned ilfe←vMagic; unsigned ilfe←vLen; char * ilfe←vStamp; /* file type specific data (optionally supplied by reader proc) */ caddr←t ilfe←rdrData; unsigned ilfe←rdrDataBytes; /* patch, text, data, bss, and common segments */ caddr←t ilfe←pAddr; unsigned ilfe←pBytes; caddr←t ilfe←tAddr; unsigned ilfe←tBytes; caddr←t ilfe←dAddr; unsigned ilfe←dBytes; caddr←t ilfe←bAddr; unsigned ilfe←bBytes; caddr←t ilfe←cAddr; unsigned ilfe←cBytes; } *XR←ILFileEntry; extern XR←ILFileEntry XR←ILGetPrevFileEntry(/* XR←ILFileEntry ilfe */); /* Return ILFileEntries in reverse order of loading. Return most-recently-loaded entry if ilfe is NIL. Return NIL at end of sequence. */ extern void XR←ILAddVersionStamp(/* XR←ILFileEntry ilfe, unsigned vMagic, unsigned vLen, caddr←t vStamp */); extern XR←ILFileEntry XR←ILAddVersionStampUsingPC(/* caddr←t pc, unsigned vMagic, unsigned vLen, char * vStamp */); /* To be called by an installation proc to record its version stamp. The vStamp pointer is stored into the XR←ILFileEntry associated with pc, without being copied; thus, it can't point to a buffer in a local frame. BEWARE: these procs don't do any locking. Concurrent calls that add version stamps for different files don't interfere with one another. */ /* * Load state symbol table */ typedef struct XR←ILSymEntryRep { char *ilse←name; unsigned ilse←type; unsigned ilse←value; unsigned ilse←size; XR←ILFileEntry ilse←ilfe; } * XR←ILSymEntry; /* ilse←type field encoding (may differ from a.out) */ #define ILSE←UNDF 0x0 /* undefined */ #define ILSE←ABS 0x2 /* absolute */ #define ILSE←TEXT 0x4 /* text */ #define ILSE←DATA 0x6 /* data */ #define ILSE←BSS 0x8 /* bss */ #define ILSE←PATCH 0x1c /* patch area address */ #define ILSE←MODULE 0x1e /* module name */ #define ILSE←EXT 01 /* external bit, or'ed in */ #define ILSE←TYPE 0x1e /* mask for all the type bits */ /* * Load state symbol lookup * * PCR retains all external or text symbols. * All these symbols are accessible by name. * Only relocatable (not absolute) symbols are accessible by value. */ /* wildcard code for wanted types */ #define WANT←ALL←TYPES ((unsigned)(-1)) /* codes for (un-)wanted classes */ #define IGNORE←NONE 0 #define IGNORE←INTERNAL 1 #define IGNORE←EXTERNAL 2 extern XR←ILSymEntry XR←ILGetMatchingSymEntryByName(/* XR←ILSymEntry ilse, char *pattern, bool caseSensitive, unsigned wantedTypes, unsigned ignoredClasses, int numToSkip */); /* A legal pattern is either (1) a symbol or (2) a symbol containing at least one dot and followed by a star: foo, bar.o, baz.c2c.o, ... -- exact match. bar.*, baz.c2c*, ... -- the star is a wildcard. Matching may be case-sensitive or not. Only symbol entries of the specified types and classes are considered. Return XR←ILSymEntry for numToSkip'th next most recent definition of symbol matching pattern, assuming that ilse points to a symbol that matches the pattern. Return NIL if no more definitions. Useful special case: (ilse == NIL) and (numToSkip == 1) returns the most recent ILSymEntry matching the specification. If (ilse != NIL), then a NIL pat value will be interpreted as the name associated with ilse. Note the resulting ILSymEntry may be undefined (i.e. have no value) if it is in the symbol table because it has been referenced but not yet defined in the loadstate. */ extern XR←ILSymEntry XR←ILGetMatchingSymEntryByValue(/* XR←ILSymEntry ilse, unsigned val, unsigned wantedTypes, unsigned ignoredClasses, int numToSkip */); /* If ilse == NIL set it to the XR←ILSymEntry for most recently defined symbol of maximum value not greater than val, of wanted type and class. Then walk numToSkip entries in the symbol table -- walk towards larger values if (numToSkip > 0), smaller values if (numToSkip < 0) -- and return the resulting XR←ILSymEntry. Return NIL if no such entry exists. Note: symbol will not be undefined. Only text, module and external symbols are guaranteed to exist in the load state. */ extern XR←Pointer XR←ILLookupProc(/* char *name, bool externOnly, bool recentOnly, */); /* Look up named procedure in load state. The externOnly and recentOnly flags constrain the search. Return NIL if symbol can't be found, or doesn't have the right type. This can be simulated with above procs; it's just a creature comfort */ /* * * Incremental Loading * */ /* Continue command to be returned from callbacks ... */ typedef char * XR←ILContinueAction; # define ilca←continue ((XR←ILContinueAction)(0)) # define ilca←dontBind ((XR←ILContinueAction)(1)) # define ilca←doBind ((XR←ILContinueAction)(2)) # define ilca←abort(msg) ((XR←ILContinueAction)(msg)) /* Utility for use from callbacks ... */ extern bool XR←ILSymIsInRecentLoad(/* XR←ILSymEntry ilse */); /* Return TRUE iff ilse is a symbol in the most recent load sequence (which may be in progress) */ /* The incremental load procs themselves ... */ extern XR←ILError XR←ILLoadFile(/* char *fName, // file name; the string will be copied. long fOffset, // offset in file (for libraries). unsigned fMagic, // file magic number hint, or 0 => use heuristics XR←ILContinueAction (*refProc)( char *sym, XR←ILSymEntry ilseOld, void *clientData ), void *refClientData, // called for each sym that is undef external in file being loaded. // ilseOld != NIL if sym exists in load state. // returns: // ilca←dontBind => create a new SymTabEntry of type UNDF|EXT. // ilca←doBind => bind to existing SymTabEntry if one exists, // else error. // ilca←continue => bind to existing SymTabEntry if one exists, // else create a new one of type UNDF|EXT. // refProc may be NIL; default action is ilca←continue. XR←ILContinueAction (*defProc)( XR←ILSymEntry ilseNew, XR←ILSymEntry ilseOld, void *clientData ), void *defClientData, // called for each symbol definition. // returns: // ilca←dontBind => create new SymTabEntry with the given value // and make any deferred relocation entries for old SymTabEntry // refer to the new one instead. // ilca←doBind => if existing SymTabEntry is undefined, define // it with given value; else error. // ilca←continue => if existing SymTabEntry is undefined, define // it with given value; else create new SymTabEntry with the // given value and make any deferred relocation entries for // the old SymTabEntry refer to the new one instead. // defProc may be NIL; default action is continue. XR←ILContinueAction (*commonProc)( char *sym, unsigned size, XR←ILSymEntry ilseOld, void *clientData ), void *commonClientData, // called for each common reference from current file. // returns: // ilca←dontBind => create new common SymTabEntry. // ilca←doBind => if existing SymTabEntry is defined, bind to // it ignoring the size specified for the common symbol; // if existing SymTabEntry is common, max the specified size // with its size; else error. // ilca←continue => if existing SymTabEntry is defined, bind to // it ignoring the size specified for the common symbol; // if existing SymTabEntry is common, max the specified size // with its size; else create new common SymTabEntry. // commonProc may be NIL, default action is continue. void (*patchSizeProc)( XR←ILFileEntry ilfe, void *clientData ), void *patchSizeClientData // called with ilfe before allocating space for the // segments. May look at segment sizes, and update // patch area size if desired. */); /* Load the specified module. Resolve external symbols from current load state. WARNING: DO NOT CALL THIS PROC RECURSIVELY E.G. FROM undefinedProc OR redefinedProc! Return NIL on success. (XR←ILFileEntry for the file just loaded is XR←ILGetPrevFileEntry(NIL)) */ extern void XR←ILEnumerateUndefinedSyms(/* bool (*func)(XR←SymEntry se, void *clientData); // return TRUE iff enumeration should continue void *clientData; */); /* Enumerate all undefined symbols. (Note: all such symbols must have been introduced since last commit.) */ extern XR←ILError XR←CommitIncrementalLoad(/* */); /* Commit all incremental loads since last commit. Fail if there are any remaining undefined symbols. Do not release lock. */ extern XR←ILError XR←AbortIncrementalLoad(/* XR←ILSymEntry ilse = NIL */); /* Abort all incremental loads since last commit (if ilse == NIL) or since the most recent commit before ilse was loaded. */ extern XR←ILError XR←InitializeIncrementalLoader(/* char *fName */); /* Initialize loadstate symbol tables for PCR itself; fName specifies the PCR object file. fName may be NIL. Return 0 on success, -XR←GetErrno() on failure. CALL EXACTLY ONCE FROM FIRST THREAD AT BEGINNING OF WORLD. */ #endif