123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- /*++
- Copyright (c) 2016 Minoca Corp. All Rights Reserved
- Module Name:
- elfcomm.c
- Abstract:
- This module implements ELF support functions that are agnostic to the
- address size (the same in 32-bit or 64-bit).
- Author:
- Evan Green 8-Apr-2016
- Environment:
- Any
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Note that elfn.h is not included here because all functions in this file
- // should be agnostic to 32 vs 64 bit. Needing to include that headers means
- // the function belongs in a different file.
- //
- #include "imp.h"
- #include "elf.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _ELF_LIBRARY_PATH_VARIABLE {
- ElfLibraryPathOrigin,
- ElfLibraryPathLib,
- ElfLibraryPathPlatform
- } ELF_LIBRARY_PATH_VARIABLE, *PELF_LIBRARY_PATH_VARIABLE;
- /*++
- Structure Description:
- This structure stores an entry in the table of variables that can be
- substituted in ELF library paths.
- Members:
- Variable - Stores the variable code.
- Name - Stores the variable name.
- --*/
- typedef struct _ELF_LIBRARY_PATH_VARIABLE_ENTRY {
- ELF_LIBRARY_PATH_VARIABLE Variable;
- PSTR Name;
- } ELF_LIBRARY_PATH_VARIABLE_ENTRY, *PELF_LIBRARY_PATH_VARIABLE_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- ImpElfPerformLibraryPathSubstitutions (
- PLOADED_IMAGE Image,
- PSTR *Path,
- PUINTN PathCapacity
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- ELF_LIBRARY_PATH_VARIABLE_ENTRY ElfLibraryPathVariables[] = {
- {ElfLibraryPathOrigin, "ORIGIN"},
- {ElfLibraryPathLib, "LIB"},
- {ElfLibraryPathPlatform, "PLATFORM"}
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- ImpElfOpenWithPathList (
- PLOADED_IMAGE Parent,
- PSTR LibraryName,
- PSTR PathList,
- PIMAGE_FILE_INFORMATION File,
- PSTR *Path
- )
- /*++
- Routine Description:
- This routine attempts to load a needed library for an ELF image.
- Arguments:
- Parent - Supplies a pointer to the image that needs the library.
- LibraryName - Supplies the name of the library to load.
- PathList - Supplies a colon-separated list of paths to try.
- File - Supplies a pointer where the information for the file including its
- open handle will be returned.
- Path - Supplies a pointer where the real path to the opened file will be
- returned. The caller is responsible for freeing this memory.
- Return Value:
- Status code.
- --*/
- {
- PSTR CompletePath;
- UINTN CompletePathCapacity;
- UINTN CompletePathSize;
- PSTR CurrentPath;
- UINTN LibraryLength;
- PSTR NextSeparator;
- UINTN PrefixLength;
- KSTATUS Status;
- LibraryLength = RtlStringLength(LibraryName);
- CompletePath = NULL;
- CompletePathCapacity = 0;
- CurrentPath = PathList;
- while (TRUE) {
- NextSeparator = RtlStringFindCharacter(CurrentPath, ':', -1);
- if (NextSeparator == NULL) {
- PrefixLength = RtlStringLength(CurrentPath);
- } else {
- PrefixLength = (UINTN)NextSeparator - (UINTN)CurrentPath;
- }
- //
- // The complete path is "prefix/library". Reallocate the buffer if
- // needed.
- //
- CompletePathSize = PrefixLength + LibraryLength + 2;
- if (CompletePathSize > CompletePathCapacity) {
- if (CompletePath != NULL) {
- ImFreeMemory(CompletePath);
- }
- CompletePath = ImAllocateMemory(CompletePathSize,
- IM_ALLOCATION_TAG);
- if (CompletePath == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
- }
- if (PrefixLength != 0) {
- RtlCopyMemory(CompletePath, CurrentPath, PrefixLength);
- if (CompletePath[PrefixLength - 1] != '/') {
- CompletePath[PrefixLength] = '/';
- PrefixLength += 1;
- }
- }
- RtlCopyMemory(CompletePath + PrefixLength,
- LibraryName,
- LibraryLength);
- CompletePath[PrefixLength + LibraryLength] = '\0';
- Status = ImpElfPerformLibraryPathSubstitutions(Parent,
- &CompletePath,
- &CompletePathCapacity);
- if (!KSUCCESS(Status)) {
- break;
- }
- Status = ImOpenFile(Parent->SystemContext, CompletePath, File);
- if (KSUCCESS(Status)) {
- break;
- }
- if (NextSeparator == NULL) {
- break;
- }
- CurrentPath = NextSeparator + 1;
- }
- //
- // If the file could be opened, get its real path.
- //
- if (KSUCCESS(Status)) {
- if (Path != NULL) {
- *Path = CompletePath;
- CompletePath = NULL;
- }
- }
- if (CompletePath != NULL) {
- ImFreeMemory(CompletePath);
- }
- return Status;
- }
- ULONG
- ImpElfOriginalHash (
- PSTR SymbolName
- )
- /*++
- Routine Description:
- This routine hashes a symbol name to get the index into the ELF hash table.
- Arguments:
- SymbolName - Supplies a pointer to the name to hash.
- Return Value:
- Returns the hash of the name.
- --*/
- {
- ULONG Hash;
- ULONG Temporary;
- Hash = 0;
- while (*SymbolName != '\0') {
- Hash = (Hash << 4) + *SymbolName;
- Temporary = Hash & 0xF0000000;
- if (Temporary != 0) {
- Hash ^= Temporary >> 24;
- }
- Hash &= ~Temporary;
- SymbolName += 1;
- }
- return Hash;
- }
- ULONG
- ImpElfGnuHash (
- PSTR SymbolName
- )
- /*++
- Routine Description:
- This routine hashes a symbol name to get the index into the ELF hash table
- using the GNU style hash function.
- Arguments:
- SymbolName - Supplies a pointer to the name to hash.
- Return Value:
- Returns the hash of the name.
- --*/
- {
- ULONG Hash;
- Hash = 5381;
- while (*SymbolName != '\0') {
- //
- // It's really hash * 33 + Character, but multiply by 33 is expanded
- // into multiply by 32 plus one.
- //
- Hash = ((Hash << 5) + Hash) + (UCHAR)*SymbolName;
- SymbolName += 1;
- }
- return Hash;
- }
- PSTR
- ImpElfGetEnvironmentVariable (
- PSTR Variable
- )
- /*++
- Routine Description:
- This routine gets an environment variable value for the image library.
- Arguments:
- Variable - Supplies a pointer to a null terminated string containing the
- name of the variable to get.
- Return Value:
- Returns a pointer to the value of the environment variable. The image
- library will not free or modify this value.
- NULL if the given environment variable is not set.
- --*/
- {
- if (ImGetEnvironmentVariable != NULL) {
- return ImGetEnvironmentVariable(Variable);
- }
- return NULL;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- ImpElfPerformLibraryPathSubstitutions (
- PLOADED_IMAGE Image,
- PSTR *Path,
- PUINTN PathCapacity
- )
- /*++
- Routine Description:
- This routine performs any variable substitutions in a library path.
- Arguments:
- Image - Supplies a pointer to the image loading the library (not the
- library itself obviously, that hasn't been loaded yet).
- Path - Supplies a pointer that on input contains the complete path. On
- output this will contain the complete path with variables expanded.
- PathCapacity - Supplies a pointer that on input contains the size of the
- path allocation. This will be updated on output if the string is
- reallocated.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated.
- --*/
- {
- PSTR CurrentPath;
- PSTR CurrentVariable;
- UINTN Delta;
- PELF_LIBRARY_PATH_VARIABLE_ENTRY Entry;
- UINTN EntryCount;
- UINTN EntryIndex;
- UINTN Index;
- PSTR Name;
- UINTN NameLength;
- PSTR NewBuffer;
- PSTR Replacement;
- UINTN ReplacementLength;
- UINTN ReplaceSize;
- UINTN ReplaceStart;
- KSTATUS Status;
- EntryCount = sizeof(ElfLibraryPathVariables) /
- sizeof(ElfLibraryPathVariables[0]);
- CurrentVariable = RtlStringFindCharacter(*Path, '$', -1);
- while (CurrentVariable != NULL) {
- //
- // Find the name of the variable and the size of the region to replace.
- //
- ReplaceStart = (UINTN)CurrentVariable - (UINTN)(*Path);
- CurrentVariable += 1;
- if (*CurrentVariable == '{') {
- CurrentVariable += 1;
- Name = CurrentVariable;
- while ((*CurrentVariable != '\0') && (*CurrentVariable != '}')) {
- CurrentVariable += 1;
- }
- if (*CurrentVariable != '}') {
- RtlDebugPrint("ELF: Missing closing brace on %s.\n", *Path);
- Status = STATUS_INVALID_SEQUENCE;
- goto ElfPerformLibraryPathSubstitutionsEnd;
- }
- NameLength = (UINTN)CurrentVariable - (UINTN)Name;
- CurrentVariable += 1;
- } else {
- Name = CurrentVariable;
- while (RtlIsCharacterAlphabetic(*CurrentVariable) != FALSE) {
- CurrentVariable += 1;
- }
- NameLength = (UINTN)CurrentVariable - (UINTN)Name;
- }
- ReplaceSize = (UINTN)CurrentVariable - (UINTN)ReplaceStart;
- //
- // Decode the variable.
- //
- for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex += 1) {
- Entry = &(ElfLibraryPathVariables[EntryIndex]);
- if ((RtlAreStringsEqual(Name, Entry->Name, NameLength) != FALSE) &&
- (Entry->Name[NameLength] == '\0')) {
- break;
- }
- }
- if (EntryIndex == EntryCount) {
- RtlDebugPrint("ELF: Warning: Unknown variable starting at %s.\n",
- Name);
- } else {
- //
- // TODO: Get the correct variable values.
- //
- ASSERT(FALSE);
- switch (Entry->Variable) {
- case ElfLibraryPathOrigin:
- Replacement = ".";
- break;
- case ElfLibraryPathLib:
- Replacement = "lib";
- break;
- case ElfLibraryPathPlatform:
- Replacement = "i386";
- break;
- default:
- ASSERT(FALSE);
- Replacement = ".";
- break;
- }
- ReplacementLength = RtlStringLength(Replacement);
- //
- // If the replacement is shorter than the original, then just
- // copy the replacement over followed by the rest.
- //
- if (ReplacementLength <= ReplaceSize) {
- CurrentPath = *Path;
- RtlCopyMemory(CurrentPath + ReplaceStart,
- Replacement,
- ReplacementLength);
- Delta = ReplaceSize - ReplacementLength;
- if (Delta != 0) {
- for (Index = ReplaceStart + ReplaceSize;
- Index < *PathCapacity - Delta;
- Index += 1) {
- CurrentPath[Index] = CurrentPath[Index + Delta];
- }
- CurrentVariable -= Delta;
- }
- //
- // The replacement is bigger than the region it's replacing.
- //
- } else {
- Delta = ReplacementLength - ReplaceSize;
- NewBuffer = ImAllocateMemory(*PathCapacity + Delta,
- IM_ALLOCATION_TAG);
- if (NewBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ElfPerformLibraryPathSubstitutionsEnd;
- }
- RtlCopyMemory(NewBuffer, *Path, ReplaceStart);
- RtlCopyMemory(NewBuffer + ReplaceStart,
- Replacement,
- ReplacementLength);
- RtlCopyMemory(NewBuffer + ReplaceStart + ReplacementLength,
- *Path + ReplaceSize,
- *PathCapacity - (ReplaceStart + ReplaceSize));
- CurrentVariable = (PSTR)((UINTN)CurrentVariable -
- (UINTN)(*Path) +
- (UINTN)NewBuffer);
- ImFreeMemory(*Path);
- *PathCapacity += Delta;
- }
- }
- //
- // Find the next variable.
- //
- CurrentVariable = RtlStringFindCharacter(CurrentVariable, '$', -1);
- }
- Status = STATUS_SUCCESS;
- ElfPerformLibraryPathSubstitutionsEnd:
- return Status;
- }
|