diff options
Diffstat (limited to 'cpukit/libdl/rtl-obj.c')
-rw-r--r-- | cpukit/libdl/rtl-obj.c | 473 |
1 files changed, 164 insertions, 309 deletions
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c index 28a5242ac3..858713dee1 100644 --- a/cpukit/libdl/rtl-obj.c +++ b/cpukit/libdl/rtl-obj.c @@ -106,7 +106,7 @@ rtems_rtl_obj_free_names (rtems_rtl_obj* obj) bool rtems_rtl_obj_free (rtems_rtl_obj* obj) { - if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0)) + if (obj->users > 0 || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0)) { rtems_rtl_set_error (EINVAL, "cannot free obj still in use"); return false; @@ -119,18 +119,63 @@ rtems_rtl_obj_free (rtems_rtl_obj* obj) rtems_rtl_obj_erase_dependents (obj); rtems_rtl_symbol_obj_erase (obj); rtems_rtl_obj_free_names (obj); - if (obj->sec_num) + if (obj->sec_num != NULL) free (obj->sec_num); - if (obj->linkmap) + if (obj->linkmap != NULL) rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap); rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj); return true; } +typedef struct rtems_rtl_obj_unresolved_data +{ + bool has_unresolved; +} rtems_rtl_obj_unresolved_data; + +static bool +rtems_rtl_obj_unresolved_dependent (rtems_rtl_obj* obj, + rtems_rtl_obj* dependent, + void* data) +{ + rtems_rtl_obj_unresolved_data* ud; + ud = (rtems_rtl_obj_unresolved_data*) data; + if ((dependent->flags & RTEMS_RTL_OBJ_DEP_VISITED) == 0) + { + dependent->flags |= RTEMS_RTL_OBJ_DEP_VISITED; + if ((dependent->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0) + ud->has_unresolved = true; + else + { + rtems_rtl_obj_iterate_dependents (dependent, + rtems_rtl_obj_unresolved_dependent, + ud); + } + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: obj: unresolved: dep: %s is %s\n", + dependent->oname, ud->has_unresolved ? "unresolved" : "resolved"); + } + return ud->has_unresolved; +} + bool rtems_rtl_obj_unresolved (rtems_rtl_obj* obj) { - return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false; + rtems_rtl_obj_unresolved_data ud = { + .has_unresolved = (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 + }; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) + printf ("rtl: obj: unresolved: dep: %s is %s\n", + obj->oname, ud.has_unresolved ? "unresolved" : "resolved"); + if (!ud.has_unresolved) + { + rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); + obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED; + rtems_rtl_obj_iterate_dependents (obj, + rtems_rtl_obj_unresolved_dependent, + &ud); + rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0); + } + return ud.has_unresolved; } bool @@ -148,6 +193,9 @@ rtems_rtl_parse_name (const char* name, * Parse the name to determine if the object file is part of an archive or it * is an object file. If an archive check the name for a '@' to see if the * archive contains an offset. + * + * Note, if an archive the object file oofset may be know but the + * object file is not. Leave the object name as a NULL. */ end = name + strlen (name); colon = strrchr (name, ':'); @@ -155,7 +203,7 @@ rtems_rtl_parse_name (const char* name, colon = end; loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true); - if (!oname) + if (!loname) { rtems_rtl_set_error (ENOMEM, "no memory for object file name"); return false; @@ -219,35 +267,6 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj* obj, const char* name) return rtems_rtl_parse_name (name, &(obj->aname), &(obj->oname), &(obj->ooffset)); } -static bool -rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer) -{ - if (lseek (fd, off, SEEK_SET) < 0) - return false; - if (read (fd, buffer, len) != len) - return false; - return true; -} - -/** - * Scan the decimal number returning the value found. - */ -static uint64_t -rtems_rtl_scan_decimal (const uint8_t* string, size_t len) -{ - uint64_t value = 0; - - while (len && (*string != ' ')) - { - value *= 10; - value += *string - '0'; - ++string; - --len; - } - - return value; -} - /** * Section size summer iterator data. */ @@ -340,22 +359,6 @@ rtems_rtl_obj_section_handler (uint32_t mask, } bool -rtems_rtl_match_name (rtems_rtl_obj* obj, const char* name) -{ - const char* n1 = obj->oname; - while ((*n1 != '\0') && (*n1 != '\n') && (*n1 != '/') && - (*name != '\0') && (*name != '/') && (*n1 == *name)) - { - ++n1; - ++name; - } - if (((*n1 == '\0') || (*n1 == '\n') || (*n1 == '/')) && - ((*name == '\0') || (*name == '/'))) - return true; - return false; -} - -bool rtems_rtl_obj_find_file (rtems_rtl_obj* obj, const char* name) { const char* pname; @@ -596,9 +599,15 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent) { rtems_rtl_obj** free_slot; rtems_chain_node* node; + if (obj == dependent || dependent == rtems_rtl_baseimage ()) return false; + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY)) + printf ("rtl: depend: add: %s -> %s\n", obj->oname, dependent->oname); + free_slot = NULL; + node = rtems_chain_first (&obj->dependents); while (!rtems_chain_is_tail (&obj->dependents, node)) { @@ -613,6 +622,7 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent) } node = rtems_chain_next (node); } + if (free_slot == NULL) { if (rtems_rtl_obj_alloc_dependents (obj, @@ -629,11 +639,47 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent) } } } + if (free_slot != NULL) *free_slot = dependent; + return free_slot != NULL; } + +bool +rtems_rtl_obj_remove_dependencies (rtems_rtl_obj* obj) +{ + /* + * If there are no references unload the object. + */ + if (obj->refs == 0) + { + /* + * Remove the refences from the object files this file depend on. The + * unload happens once the list of objects to be unloaded has been made and + * the destructors have been called for all those modules. + */ + rtems_chain_node* node = rtems_chain_first (&obj->dependents); + while (!rtems_chain_is_tail (&obj->dependents, node)) + { + rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; + size_t d; + for (d = 0; d < depends->dependents; ++d) + { + if (depends->depends[d] != NULL) + { + rtems_rtl_obj_dec_reference (depends->depends[d]); + depends->depends[d] = NULL; + } + } + node = rtems_chain_next (node); + } + return true; + } + return false; +} + bool rtems_rtl_obj_iterate_dependents (rtems_rtl_obj* obj, rtems_rtl_obj_depends_iterator iterator, @@ -1065,244 +1111,42 @@ rtems_rtl_obj_run_cdtors (rtems_rtl_obj* obj, uint32_t mask) } } -void -rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj) +static bool +rtems_rtl_obj_cdtors_to_run (rtems_rtl_obj* obj, uint32_t mask) { - return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR); + rtems_chain_node* node = rtems_chain_first (&obj->sections); + while (!rtems_chain_is_tail (&obj->sections, node)) + { + rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node; + if ((sect->flags & mask) == mask) + return true; + node = rtems_chain_next (node); + } + return false; } -void -rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj) +bool +rtems_rtl_obj_ctors_to_run (rtems_rtl_obj* obj) { - return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR); + return rtems_rtl_obj_cdtors_to_run (obj, RTEMS_RTL_OBJ_SECT_CTOR); } -/** - * Find a module in an archive returning the offset in the archive in the - * object descriptor. - */ -static bool -rtems_rtl_obj_archive_find (rtems_rtl_obj* obj, int fd) -{ -#define RTEMS_RTL_AR_IDENT "!<arch>\n" -#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1) -#define RTEMS_RTL_AR_FHDR_BASE RTEMS_RTL_AR_IDENT_SIZE -#define RTEMS_RTL_AR_FNAME (0) -#define RTEMS_RTL_AR_FNAME_SIZE (16) -#define RTEMS_RTL_AR_SIZE (48) -#define RTEMS_RTL_AR_SIZE_SIZE (10) -#define RTEMS_RTL_AR_MAGIC (58) -#define RTEMS_RTL_AR_MAGIC_SIZE (2) -#define RTEMS_RTL_AR_FHDR_SIZE (60) - - size_t fsize = obj->fsize; - off_t extended_file_names; - uint8_t header[RTEMS_RTL_AR_FHDR_SIZE]; - bool scanning; - - if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) != RTEMS_RTL_AR_IDENT_SIZE) - { - rtems_rtl_set_error (errno, "reading archive identifer"); - return false; - } - - if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0) - { - rtems_rtl_set_error (EINVAL, "invalid archive identifer"); - return false; - } - - /* - * Seek to the current offset in the archive and if we have a valid archive - * file header present check the file name for a match with the oname field - * of the object descriptor. If the archive header is not valid and it is the - * first pass reset the offset and start the search again in case the offset - * provided is not valid any more. - * - * The archive can have a symbol table at the start. Ignore it. A symbol - * table has the file name '/'. - * - * The archive can also have the GNU extended file name table. This - * complicates the processing. If the object's file name starts with '/' the - * remainder of the file name is an offset into the extended file name - * table. To find the extended file name table we need to scan from start of - * the archive for a file name of '//'. Once found we remeber the table's - * start and can direct seek to file name location. In other words the scan - * only happens once. - * - * If the name had the offset encoded we go straight to that location. - */ - - if (obj->ooffset != 0) - scanning = false; - else - { - scanning = true; - obj->ooffset = RTEMS_RTL_AR_FHDR_BASE; - } - - extended_file_names = 0; - - while (obj->ooffset < fsize) - { - /* - * Clean up any existing data. - */ - memset (header, 0, sizeof (header)); - - if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0])) - { - rtems_rtl_set_error (errno, "seek/read archive file header"); - obj->ooffset = 0; - obj->fsize = 0; - return false; - } - - if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) || - (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a)) - { - if (scanning) - { - rtems_rtl_set_error (EINVAL, "invalid archive file header"); - obj->ooffset = 0; - obj->fsize = 0; - return false; - } - - scanning = true; - obj->ooffset = RTEMS_RTL_AR_FHDR_BASE; - continue; - } - - /* - * The archive header is always aligned to an even address. - */ - obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE], - RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1; - - /* - * Check for the GNU extensions. - */ - if (header[0] == '/') - { - off_t extended_off; - - switch (header[1]) - { - case ' ': - /* - * Symbols table. Ignore the table. - */ - break; - case '/': - /* - * Extended file names table. Remember. - */ - extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* - * Offset into the extended file name table. If we do not have the - * offset to the extended file name table find it. - */ - extended_off = - rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE); - - if (extended_file_names == 0) - { - off_t off = obj->ooffset; - while (extended_file_names == 0) - { - off_t esize = - (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE], - RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1; - off += esize + RTEMS_RTL_AR_FHDR_SIZE; - - if (!rtems_rtl_seek_read (fd, off, - RTEMS_RTL_AR_FHDR_SIZE, &header[0])) - { - rtems_rtl_set_error (errno, - "seeking/reading archive ext file name header"); - obj->ooffset = 0; - obj->fsize = 0; - return false; - } - - if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) || - (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a)) - { - rtems_rtl_set_error (errno, "invalid archive file header"); - obj->ooffset = 0; - obj->fsize = 0; - return false; - } - - if ((header[0] == '/') && (header[1] == '/')) - { - extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE; - break; - } - } - } - - if (extended_file_names) - { - /* - * We know the offset in the archive to the extended file. Read the - * name from the table and compare with the name we are after. - */ -#define RTEMS_RTL_MAX_FILE_SIZE (256) - char name[RTEMS_RTL_MAX_FILE_SIZE]; - - if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off, - RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0])) - { - rtems_rtl_set_error (errno, - "invalid archive ext file seek/read"); - obj->ooffset = 0; - obj->fsize = 0; - return false; - } - - if (rtems_rtl_match_name (obj, name)) - { - obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE; - return true; - } - } - break; - default: - /* - * Ignore the file because we do not know what it it. - */ - break; - } - } - else - { - if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME])) - { - obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE; - return true; - } - } +void +rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj) +{ + rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR); +} - obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE; - } +bool +rtems_rtl_obj_dtors_to_run (rtems_rtl_obj* obj) +{ + return rtems_rtl_obj_cdtors_to_run (obj, RTEMS_RTL_OBJ_SECT_DTOR); +} - rtems_rtl_set_error (ENOENT, "object file not found"); - obj->ooffset = 0; - obj->fsize = 0; - return false; +void +rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj) +{ + rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR); } static bool @@ -1323,31 +1167,16 @@ rtems_rtl_obj_file_load (rtems_rtl_obj* obj, int fd) return false; } -static bool -rtems_rtl_obj_file_unload (rtems_rtl_obj* obj) +static void +rtems_rtl_obj_set_error (int num, const char* text) { - if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS) - { - rtems_chain_node* node; - - if (!loaders[obj->format].unload (obj)) - return false; - - node = rtems_chain_first (&obj->dependents); - while (!rtems_chain_is_tail (&obj->dependents, node)) - { - rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; - size_t d; - for (d = 0; d < depends->dependents; ++d) - { - if (depends->depends[d] != NULL) - rtems_rtl_obj_dec_reference (depends->depends[d]); - } - node = rtems_chain_next (node); - } - } + rtems_rtl_set_error (num, text); +} - return false; +size_t +rtems_rtl_obj_get_reference (rtems_rtl_obj* obj) +{ + return obj->refs; } void @@ -1364,6 +1193,14 @@ rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj) } bool +rtems_rtl_obj_orphaned (rtems_rtl_obj* obj) +{ + return ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == 0 && + obj->users == 0 && + rtems_rtl_obj_get_reference (obj) == 0); +} + +bool rtems_rtl_obj_load (rtems_rtl_obj* obj) { int fd; @@ -1377,7 +1214,7 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj) fd = open (rtems_rtl_obj_fname (obj), O_RDONLY); if (fd < 0) { - rtems_rtl_set_error (ENOMEM, "opening for object file"); + rtems_rtl_set_error (errno, "opening for object file"); return false; } @@ -1387,7 +1224,14 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj) */ if (rtems_rtl_obj_aname_valid (obj)) { - if (!rtems_rtl_obj_archive_find (obj, fd)) + off_t enames = 0; + if (!rtems_rtl_obj_archive_find_obj (fd, + obj->fsize, + &obj->oname, + &obj->ooffset, + &obj->fsize, + &enames, + rtems_rtl_obj_set_error)) { close (fd); return false; @@ -1403,7 +1247,10 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj) return false; } - if (!_rtld_linkmap_add (obj)) /* For GDB */ + /* + * For GDB + */ + if (!_rtld_linkmap_add (obj)) { close (fd); return false; @@ -1417,7 +1264,15 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj) bool rtems_rtl_obj_unload (rtems_rtl_obj* obj) { - _rtld_linkmap_delete(obj); - rtems_rtl_obj_file_unload (obj); - return true; + bool ok = false; + if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS) + { + _rtld_linkmap_delete(obj); + ok = loaders[obj->format].unload (obj); + } + else + { + rtems_rtl_set_error (EINVAL, "invalid object loader format"); + } + return ok; } |