/* 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 */ /* * XR_IL.h * * Demers July 14, 1992 */ /* * * 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_IL_h #define __XR_IL_h #include #include /* * 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(void); /* 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; XR_size_t ilfe_fSize; XR_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) */ XR_caddr_t ilfe_rdrData; unsigned ilfe_rdrDataBytes; /* patch, text, data, bss, and common segments */ XR_caddr_t ilfe_pAddr; unsigned ilfe_pBytes; XR_caddr_t ilfe_tAddr; unsigned ilfe_tBytes; XR_caddr_t ilfe_dAddr; unsigned ilfe_dBytes; XR_caddr_t ilfe_bAddr; unsigned ilfe_bBytes; XR_caddr_t ilfe_cAddr; unsigned ilfe_cBytes; void * ilfe__under; /* -> internal data structure */ } *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, XR_caddr_t vStamp ); extern XR_ILFileEntry XR_ILAddVersionStampUsingPC( XR_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; void * ilse__under; /* -> internal data structure */ } * 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, const 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. */ /* * even more obsolete stuff */ extern XR_ILSymEntry XR_ILLookupSymEntry(const char *sym, bool externOnly); /* Case-sensitive symbol entry lookup. Return NIL on failure. */ extern XR_ILSymEntry XR_ILGetPrevSymEntry(XR_ILSymEntry ilse, bool externOnly); /* Next most recent version of symbol defined by ilse. */ /* * * 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 and elsewhere ... */ 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_ILSymEntry ilse, 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.) THIS WORKS ONLY AFTER A FAILED COMMIT. */ extern XR_ILError XR_CommitIncrementalLoad(void); /* 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); /* 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. CALL EXACTLY ONCE FROM FIRST THREAD AT BEGINNING OF WORLD. */ #endif /* __XR_IL_h */