about summary refs log tree commit diff stats
path: root/src/librarian
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-04-10 18:51:07 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-04-10 18:51:16 +0200
commit5d6307184941f6f2171153df6a5bb0105fcbce9e (patch)
treec0c31a50eac0c58725ba8418154ca48a3c4ae2a9 /src/librarian
parent8c98c7b67580b2807d37fa03f59416f4526df770 (diff)
downloadbox64-5d6307184941f6f2171153df6a5bb0105fcbce9e.tar.gz
box64-5d6307184941f6f2171153df6a5bb0105fcbce9e.zip
[ELFLOADER] Improved handling of Failed-to-load library (and unloading of libs too)
Diffstat (limited to 'src/librarian')
-rwxr-xr-xsrc/librarian/librarian.c80
-rwxr-xr-xsrc/librarian/library.c81
-rwxr-xr-xsrc/librarian/library_private.h4
3 files changed, 112 insertions, 53 deletions
diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c
index e3cca3de..f704239d 100755
--- a/src/librarian/librarian.c
+++ b/src/librarian/librarian.c
@@ -39,13 +39,10 @@ void FreeLibrarian(lib_t **maplib, x64emu_t *emu)
     library_t* owner = (*maplib)->owner;
     (*maplib)->owner = NULL;    // to avoid recursive free...
 
-    // free the memory only. All the uninit logic is elsewhere
-
-    
     if((*maplib)->ownlibs && (*maplib)->libsz) {
         for(int i=0; i<(*maplib)->libsz; ++i) {
             printf_log(LOG_DEBUG, "Unloading %s\n", (*maplib)->libraries[i]->name);
-            Free1Library(&(*maplib)->libraries[i], emu);
+            DecRefCount(&(*maplib)->libraries[i], emu);
         }
     }
     box_free((*maplib)->libraries);
@@ -108,8 +105,6 @@ void MapLibAddLib(lib_t* maplib, library_t* lib)
     ++maplib->libsz;
 }
 
-static void MapLibRemoveLib(lib_t* maplib, library_t* lib);
-
 static void MapLibAddMapLib(lib_t* dest, library_t* lib_src, lib_t* src)
 {
     if(!src)
@@ -130,7 +125,7 @@ static void MapLibAddMapLib(lib_t* dest, library_t* lib_src, lib_t* src)
         FreeLibrarian(&src, NULL);
 }
 
-static void MapLibRemoveLib(lib_t* maplib, library_t* lib)
+void MapLibRemoveLib(lib_t* maplib, library_t* lib)
 {
     if(!maplib || !lib)
         return;
@@ -240,9 +235,9 @@ int AddNeededLib_add(lib_t* maplib, int local, needed_libs_t* needed, int n, box
             printf_log(LOG_DEBUG, "Failure to add lib linkmap\n");
             return 1;
         }
-        lm->l_addr = (Elf64_Addr)GetElfDelta(my_context->elfs[lib->e.elf_index]);
+        lm->l_addr = (Elf64_Addr)GetElfDelta(lib->e.elf);
         lm->l_name = lib->name;
-        lm->l_ld = GetDynamicSection(my_context->elfs[lib->e.elf_index]);
+        lm->l_ld = GetDynamicSection(lib->e.elf);
     }
     return 0;
 }
@@ -254,14 +249,14 @@ int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, box
     if(!maplib)
         maplib = (local)?lib->maplib:my_context->maplib;
 
-    int mainelf = GetElfIndex(lib);
+    elfheader_t* mainelf = GetElf(lib);
 
-    if(mainelf==-1) {
+    if(!mainelf) {
         // It's a native libs, nothing else to do
     } else {
         // it's an emulated lib, 
         // load dependancies and launch init sequence
-        if(LoadNeededLibs(box64->elfs[mainelf], maplib, 0, bindnow, box64, emu)) {
+        if(LoadNeededLibs(mainelf, maplib, 0, bindnow, box64, emu)) {
             printf_log(LOG_DEBUG, "Failure to Add dependant lib => fail\n");
             return 1;
         }
@@ -296,6 +291,16 @@ int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, box
     
     return 0;
 }
+void AddNeededLib_remove(lib_t* maplib, int local, library_t** lib, box64context_t* box64, x64emu_t* emu)
+{
+    
+    if(!lib || !*lib)    // no lib, error is already detected, no need to return a new one
+        return;
+    if(!maplib)
+        maplib = (local)?(*lib)->maplib:my_context->maplib;
+
+    DecRefCount(lib, emu);
+}
 
 EXPORTDYN
 int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, box64context_t* box64, x64emu_t* emu)
@@ -311,12 +316,29 @@ int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, b
             ret = 1;
         }
     }
+    // error while loadind lib, unload...
+    if(ret) {
+        for(int i=0; i<needed->size; ++i) {
+            if(box64_log>=LOG_DEBUG && needed->libs[i])
+                printf_log(LOG_DEBUG, "Will decref after failed load %s\n", needed->names[i]);
+            AddNeededLib_remove(maplib, local, &needed->libs[i], box64, emu);
+        }
+        return ret;
+    }
     // add dependant libs and init them
     for (int i=0; i<needed->size; ++i)
         if(AddNeededLib_init(maplib, local, bindnow, needed->libs[i], box64, emu)) {
             printf_log(LOG_INFO, "Error initializing needed lib %s\n", needed->names[i]);
             if(!allow_missing_libs) ret = 1;
         }
+    // error while loadind lib, unload...
+    if(ret) {
+        for(int i=0; i<needed->size; ++i) {
+            if(box64_log>=LOG_DEBUG && needed->libs[i])
+                printf_log(LOG_DEBUG, "Will remove after failed init %s\n", needed->names[i]);
+            AddNeededLib_remove(maplib, local, &needed->libs[i], box64, emu);
+        }
+    }
     return ret;
 }
 
@@ -365,13 +387,13 @@ int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
     if(go<0)
         go = 0; // not found...
     for(int i=go; i<maplib->libsz; ++i) {
-        if(GetElfIndex(maplib->libraries[i])==-1 || (my_context->elfs[GetElfIndex(maplib->libraries[i])]!=self))
+        if(GetElfIndex(maplib->libraries[i])==-1 || (GetElf(maplib->libraries[i])!=self))
             if(GetLibGlobalSymbolStartEnd(maplib->libraries[i], name, start, end, size, &weak, version, vername, 0, globdefver))
                 if(*start)
                     return 1;
     }
     for(int i=go; i<maplib->libsz; ++i)
-        if(GetElfIndex(maplib->libraries[i])==-1 || (my_context->elfs[GetElfIndex(maplib->libraries[i])]!=self))
+        if(GetElfIndex(maplib->libraries[i])==-1 || (GetElf(maplib->libraries[i])!=self))
             GetLibWeakSymbolStartEnd(maplib->libraries[i], name, start, end, size, &weak, version, vername, 0, weakdefver);
     // loop done, weak symbol found
     if(weak && *start)
@@ -387,13 +409,13 @@ int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
                     weak = 1;
         }
         for(int i=0; i<go; ++i) {
-            if(GetElfIndex(maplib->libraries[i])==-1 || (my_context->elfs[GetElfIndex(maplib->libraries[i])]!=self))
+            if(GetElfIndex(maplib->libraries[i])==-1 || (GetElf(maplib->libraries[i])!=self))
                 if(GetLibGlobalSymbolStartEnd(maplib->libraries[i], name, start, end, size, &weak, version, vername, 1, globdefver))
                     if(*start)
                         return 1;
         }
         for(int i=0; i<go; ++i) {
-            if(GetElfIndex(maplib->libraries[i])==-1 || (my_context->elfs[GetElfIndex(maplib->libraries[i])]!=self))
+            if(GetElfIndex(maplib->libraries[i])==-1 || (GetElf(maplib->libraries[i])!=self))
                 GetLibWeakSymbolStartEnd(maplib->libraries[i], name, start, end, size, &weak, version, vername, 1, weakdefver);
         }
     if(weak && *start)
@@ -518,15 +540,15 @@ elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, co
         return my_context->elfs[0];
     for(int i=0; i<maplib->libsz; ++i) {
         if(GetLibGlobalSymbolStartEnd(maplib->libraries[i], name, &start, &end, size, &weak, version, vername, 1, defver)) {
-            int idx = GetElfIndex(maplib->libraries[i]);
-            if(idx==-1) {
+            elfheader_t* h = GetElf(maplib->libraries[i]);
+            if(!h) {
                 printf_log(LOG_NONE, "Warning, getting Elf info for a native symbol \"%s\" from lib \"%s\"\n", name, GetNameLib(maplib->libraries[i]));
                 return NULL;
             }
             if(weak)
-                ret = my_context->elfs[idx];
+                ret = h;
             else
-                return my_context->elfs[idx];
+                return h;
         }
     }
 
@@ -535,15 +557,15 @@ elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, co
         ret = my_context->elfs[0];
     for(int i=0; i<maplib->libsz; ++i) {
         if(GetLibWeakSymbolStartEnd(maplib->libraries[i], name, &start, &end, size, &weak, version, vername, 1, defver)) {
-            int idx = GetElfIndex(maplib->libraries[i]);
-            if(idx==-1) {
+            elfheader_t* h = GetElf(maplib->libraries[i]);
+            if(!h) {
                 printf_log(LOG_NONE, "Warning, getting Elf info for a native symbol \"%s\" from lib \"%s\"\n", name, GetNameLib(maplib->libraries[i]));
                 return NULL;
             }
             if(weak)
-                ret = my_context->elfs[idx];
+                ret = h;
             else
-                return my_context->elfs[idx];
+                return h;
         }
     }
     // return what has been found (maybe nothing)
@@ -597,7 +619,7 @@ int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, ui
             return 0;
     }
     for(int i=0; i<maplib->libsz; ++i) {
-        if(GetElfIndex(maplib->libraries[i])!=-1 && (!self || my_context->elfs[GetElfIndex(maplib->libraries[i])]==self)) {
+        if(GetElfIndex(maplib->libraries[i])!=-1 && (!self || GetElf(maplib->libraries[i])==self)) {
             if(GetLibLocalSymbolStartEnd(maplib->libraries[i], name, start, end, size, &weak, version, vername, 1, defver))
                 if(*start || *end)
                     return 1;
@@ -633,15 +655,15 @@ const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint64_t* sz, c
                 *lib = NULL;    // main elf
             else {
                 for(int i=0; i<my_context->maplib->libsz; ++i) {
-                    int idx = GetElfIndex(my_context->maplib->libraries[i]);
-                    if((idx!=-1) && (my_context->elfs[idx]==h)) {
+                    elfheader_t* head = GetElf(my_context->maplib->libraries[i]);
+                    if((head) && (head==h)) {
                         *lib = my_context->maplib->libraries[i];
                         return ret;
                     }
                 }
                 for(int i=0; i<my_context->local_maplib->libsz; ++i) {
-                    int idx = GetElfIndex(my_context->local_maplib->libraries[i]);
-                    if((idx!=-1) && (my_context->elfs[idx]==h)) {
+                    elfheader_t* head = GetElf(my_context->local_maplib->libraries[i]);
+                    if((head) && (head==h)) {
                         *lib = my_context->local_maplib->libraries[i];
                         return ret;
                     }
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 6a88b5c2..20b663db 100755
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -416,7 +416,6 @@ int AddSymbolsLibrary(lib_t *maplib, library_t* lib, x64emu_t* emu)
 {
     (void)emu;
 
-    lib->active = 1;
     if(lib->type==LIB_EMULATED) {
         elfheader_t *elf_header = lib->e.elf;
         // add symbols
@@ -465,7 +464,6 @@ int FinalizeLibrary(library_t* lib, lib_t* local_maplib, int bindnow, x64emu_t*
 
 int ReloadLibrary(library_t* lib, x64emu_t* emu)
 {
-    lib->active = 1;
     if(lib->type==LIB_EMULATED) {
         elfheader_t *elf_header = lib->e.elf;
         // reload image in memory and re-run the mapping
@@ -510,33 +508,31 @@ int ReloadLibrary(library_t* lib, x64emu_t* emu)
 
 int FiniLibrary(library_t* lib, x64emu_t* emu)
 {
-    if(!lib->active)
-        return 0;   // nothing to do
     switch (lib->type) {
         case LIB_WRAPPED:
-            if(!--lib->w.refcnt)
-                lib->active = 0;
             return 0;
         case LIB_EMULATED:
-            if(!--lib->e.elf->refcnt) {
-                if(emu)
-                    RunElfFini(lib->e.elf, emu);
-                lib->active = 0;
-            }
+            RunElfFini(lib->e.elf, emu);
             return 0;
     }
     return 1;   // bad type
 }
 
-void InactiveLibrary(library_t* lib)
-{
-    lib->active = 0;
-}
-
 void Free1Library(library_t **lib, x64emu_t* emu)
 {
     if(!(*lib)) return;
 
+    printf_log(LOG_DEBUG, "Free1Library %s\n", (*lib)->name);
+    // remove lib from maplib/local_maplib...
+    if(my_context) {
+        MapLibRemoveLib(my_context->maplib, *lib);
+        MapLibRemoveLib(my_context->local_maplib, *lib);
+    }
+    // free elf is relevant
+    if((*lib)->type==LIB_EMULATED) {
+        FreeElfHeader(&(*lib)->e.elf);
+    }
+
     // No "Fini" logic here, only memory handling
     if((*lib)->maplib)
         FreeLibrarian(&(*lib)->maplib, emu);
@@ -624,7 +620,7 @@ int IsSameLib(library_t* lib, const char* path)
 }
 int GetLibWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, size_t size, int* weak, int version, const char* vername, int local, const char* defver)
 {
-    if(!name[0] || !lib->active)
+    if(!name[0])
         return 0;
     khint_t k;
     // get a new symbol
@@ -651,7 +647,7 @@ int GetLibWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start,
 }
 int GetLibGlobalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, size_t size, int* weak, int version, const char* vername, int local, const char* defver)
 {
-    if(!name[0] || !lib || !lib->active)
+    if(!name[0] || !lib)
         return 0;
     khint_t k;
     // get a new symbol
@@ -678,7 +674,7 @@ int GetLibGlobalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* star
 }
 int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, size_t size, int* weak, int version, const char* vername, int local, const char* defver)
 {
-    if(!name[0] || !lib->active)
+    if(!name[0])
         return 0;
     khint_t k;
     // get a new symbol
@@ -907,8 +903,6 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
 
 int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size, int* weak, int version, const char* vername, int local)
 {
-    if(!lib->active)
-        return 0;
     if(version==-2) // don't send global native symbol for a version==-2 search
         return 0;
     // check in datamaps (but no version, it's not handled there)
@@ -1063,8 +1057,6 @@ void IncRefCount(library_t* lib, x64emu_t* emu)
 {
     if(lib->type==LIB_UNNKNOW)
         return;
-    if(!lib->active)
-        ReloadLibrary(lib, emu);
     switch (lib->type) {
         case LIB_WRAPPED:
             ++lib->w.refcnt;
@@ -1072,4 +1064,47 @@ void IncRefCount(library_t* lib, x64emu_t* emu)
         case LIB_EMULATED:
             ++lib->e.elf->refcnt;
     }
+}
+
+int DecRefCount(library_t** lib, x64emu_t* emu)
+{
+    if(!lib || !*lib)
+        return 0;
+    if((*lib)->type==LIB_UNNKNOW)
+        return 0;
+    int ret = 0;
+    switch ((*lib)->type) {
+        case LIB_WRAPPED:
+            if(!(ret=--(*lib)->w.refcnt)) {
+                if((*lib)->w.needed)
+                    for(int i=0; i<(*lib)->w.needed->size; ++i)
+                        DecRefCount(&(*lib)->w.needed->libs[i], emu);
+                Free1Library(lib, emu);
+            }
+            break;
+        case LIB_EMULATED:
+            if(!(ret=--(*lib)->e.elf->refcnt)) {
+                if((*lib)->e.elf->needed)
+                    for(int i=0; i<(*lib)->e.elf->needed->size; ++i)
+                        DecRefCount(&(*lib)->e.elf->needed->libs[i], emu);
+                removeLinkMapLib(*lib);
+                FiniLibrary(*lib, emu);
+                Free1Library(lib, emu);
+            }
+            break;
+    }
+    return ret;
+}
+
+int GetRefCount(library_t* lib)
+{
+    switch (lib->type) {
+        case LIB_WRAPPED:
+            return lib->w.refcnt;
+            break;
+        case LIB_EMULATED:
+            return lib->e.elf->refcnt;
+        default:
+            return 0;
+    }
 }
\ No newline at end of file
diff --git a/src/librarian/library_private.h b/src/librarian/library_private.h
index 2b2c5eff..bb8188d8 100755
--- a/src/librarian/library_private.h
+++ b/src/librarian/library_private.h
@@ -62,7 +62,6 @@ typedef struct library_s {
     char*               path;   // original path
     int                 nbdot;  // nombre of "." after .so
     int                 type;   // 0: native(wrapped) 1: emulated(elf) -1: undetermined
-    int                 active;
     wrappedlib_fini_t   fini;
     wrappedlib_get_t    getglobal;  // get global (non-weak)
     wrappedlib_get_t    getweak;    // get weak symbol
@@ -112,4 +111,7 @@ linkmap_t* getLinkMapLib(library_t* lib);
 linkmap_t* addLinkMapLib(library_t* lib);
 void removeLinkMapLib(library_t* lib);
 
+int FiniLibrary(library_t* lib, x64emu_t* emu);
+void Free1Library(library_t **lib, x64emu_t* emu);
+
 #endif //__LIBRARY_PRIVATE_H_