]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - qnx/src/ipc3x_dev/ti/syslink/procMgr/hlos/knl/loaders/Elf/Qnx/DLOAD/DLOAD_SYM/symtab.c
4d8f306f4eeda92be8b813c05c15dd13a3d47105
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / DLOAD / DLOAD_SYM / symtab.c
1 /*
2 * symtab.c
3 *
4 * Symbol table creation, maintenance, and management.  This module also
5 * contains implementations of local and global symbol table lookup
6 * algorithms, as appropriate for the platform that we are running on
7 * (assumed to be DSP Bridge or Linux model, indicated by
8 * direct_dependent_only flag in a given Module).
9 *
10 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
11 *
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the
23 * distribution.
24 *
25 * Neither the name of Texas Instruments Incorporated nor the names of
26 * its contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 */
43 #include "elf32.h"
44 #include "ArrayList.h"
46 /*---------------------------------------------------------------------------*/
47 /* Set up a Queue of Int32 type data objects.                                */
48 /*---------------------------------------------------------------------------*/
49 #include "Queue.h"
50 TYPE_QUEUE_DEFINITION(int32_t, Int32)
51 TYPE_QUEUE_IMPLEMENTATION(int32_t, Int32)
53 #include "symtab.h"
54 #include "dload_api.h"
55 #include "dload.h"
56 #if defined (__KERNEL__)
57 #include <linux/string.h>
58 #else
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #endif
64 #undef LOADER_DEBUG
65 #define LOADER_DEBUG 0
66 /*---------------------------------------------------------------------------*/
67 /* Holds the handle of the ET_EXEC-type mmodule loaded, if any.              */
68 /*---------------------------------------------------------------------------*/
69 int32_t DLIMP_application_handle = 0;
71 /*****************************************************************************/
72 /* DLSYM_COPY_GLOBALS() - Copy global symbols from the dynamic module's      */
73 /*      symbol table to the loader's global symbol table.                    */
74 /*****************************************************************************/
75 void DLSYM_copy_globals(DLIMP_Dynamic_Module *dyn_module)
76 {
77    Elf32_Word i, global_index, global_symnum;
78    DLIMP_Loaded_Module *module = dyn_module->loaded_module;
80 #if LOADER_DEBUG
81    if (debugging_on)
82       DLIF_trace("DLSYM_copy_globals:\n");
83 #endif
85    /*------------------------------------------------------------------------*/
86    /* The dynamic symbol table is sorted so that the local symbols come      */
87    /* before the global symbols. gsymtab_offset points to the address where   */
88    /* the first global symbol starts. Only the global symbols need to be     */
89    /* copied into the persistent info.                                       */
90    /*------------------------------------------------------------------------*/
91    global_index  = dyn_module->gsymtab_offset / sizeof(struct Elf32_Sym);
92    global_symnum = dyn_module->symnum - global_index;
94    /*------------------------------------------------------------------------*/
95    /* Create space for the new global symbol table.                          */
96    /*------------------------------------------------------------------------*/
98    if (module->gsymtab)
99        DLIF_free(module->gsymtab);
100    module->gsymtab = DLIF_malloc(sizeof(struct Elf32_Sym) * global_symnum);
101    module->gsymnum = global_symnum;
103    if (module->gsymtab)
104       memcpy(module->gsymtab,
105              &dyn_module->symtab[global_index],
106              sizeof(struct Elf32_Sym) * global_symnum);
108    /*------------------------------------------------------------------------*/
109    /* Copy the string table part that contains the global symbol names.      */
110    /*------------------------------------------------------------------------*/
111    if (module->gstrtab)
112        DLIF_free(module->gstrtab);
114    module->gstrsz  = dyn_module->strsz - dyn_module->gstrtab_offset;
115    module->gstrtab = DLIF_malloc(module->gstrsz);
117    if (module->gstrtab)
118       memcpy(module->gstrtab,
119              dyn_module->strtab + dyn_module->gstrtab_offset,
120              module->gstrsz);
122    /*------------------------------------------------------------------------*/
123    /* Update the symbol names of the global symbol entries to point to       */
124    /* the symbol names in the string table.                                  */
125    /* NOTE: Note that we don't set the offset into the string table. We      */
126    /* instead set the full address so that the st_name field can be accessed */
127    /* as char *.                                                             */
128    /*------------------------------------------------------------------------*/
129    for (i = 0; i < global_symnum; i++)
130    {
132       Elf32_Word old_offset = dyn_module->symtab[i + global_index].st_name -
133                               (Elf32_Addr) dyn_module->strtab;
134       Elf32_Word new_offset = old_offset - dyn_module->gstrtab_offset;
135       if(module->gsymtab) {
136          struct Elf32_Sym *sym = &((struct Elf32_Sym*)(module->gsymtab))[i];
137          sym->st_name = new_offset + (Elf32_Addr)module->gstrtab;
138       }
139 #if LOADER_DEBUG
140       if (debugging_on) DLIF_trace("Copying symbol: %s\n", (char *)
141                                  dyn_module->symtab[i + global_index].st_name);
142 #endif
143    }
146 /*****************************************************************************/
147 /* BREADTH_FIRST_LOOKUP() - Perform a breadth-first search of the Module     */
148 /*     dependency graph to find specified symbol name (sym_name).            */
149 /*****************************************************************************/
150 static BOOL breadth_first_lookup(DLOAD_HANDLE phandle,
151                                  const char* sym_name,
152                                  int handle,
153                                  Elf32_Addr *sym_value)
155    /*------------------------------------------------------------------------*/
156    /* We start this function by putting the specified file handle on the     */
157    /* file_handle_queue.                                                     */
158    /*------------------------------------------------------------------------*/
159    Int32_Queue file_handle_queue;
160    Int32_initialize_queue(&file_handle_queue);
161    Int32_enqueue(&file_handle_queue, handle);
162    LOADER_OBJECT *dHandle = (LOADER_OBJECT *)phandle;
164    /*------------------------------------------------------------------------*/
165    /* While the queue is not empty, keep looking for the symbol.             */
166    /*------------------------------------------------------------------------*/
167    while(file_handle_queue.size)
168    {
169       int i;
171       /*---------------------------------------------------------------------*/
172       /* Set up a pointer to front of the list of loaded files so that we    */
173       /* can be sure that dependent files will be searched in load order.    */
174       /*---------------------------------------------------------------------*/
175       loaded_module_ptr_Queue_Node* mod_node =
176                                      dHandle->DLIMP_loaded_objects.front_ptr;
177       int* dependencies = (int*)(mod_node->value->dependencies.buf);
179       /*---------------------------------------------------------------------*/
180       /* Pluck off the file handle at the front of the file_handle_queue.    */
181       /* We will search this file next.                                      */
182       /*---------------------------------------------------------------------*/
183       handle = Int32_dequeue(&file_handle_queue);
185       /*---------------------------------------------------------------------*/
186       /* Locate the Module associated with the current file handle.          */
187       /*---------------------------------------------------------------------*/
188       while (mod_node->value->file_handle != handle) mod_node++;
190       /*---------------------------------------------------------------------*/
191       /* Search the symbol table of the current file handle's Module.        */
192       /* If the symbol was found, then we're finished.                       */
193       /*---------------------------------------------------------------------*/
194       if (DLSYM_lookup_global_symtab(sym_name,
195                                      mod_node->value->gsymtab,
196                                      mod_node->value->gsymnum,
197                                      sym_value))
198          return TRUE;
200       /*---------------------------------------------------------------------*/
201       /* If our symbol was not in the current Module, then add this Module's */
202       /* dependents to the end of the file_handle_queue.                     */
203       /*---------------------------------------------------------------------*/
204       for (i = 0; i < mod_node->value->dependencies.size; i++)
205          Int32_enqueue(&file_handle_queue, dependencies[i]);
206    }
208    /*------------------------------------------------------------------------*/
209    /* We didn't find our symbol; return FALSE.                               */
210    /*------------------------------------------------------------------------*/
211    return FALSE;
214 /*****************************************************************************/
215 /* DLSYM_global_lookup() - Search the global symbol table to find the        */
216 /*                         definition of the given symbol name.              */
217 /*****************************************************************************/
218 BOOL DLSYM_global_lookup(DLOAD_HANDLE handle,
219                          const char    *sym_name,
220                          DLIMP_Loaded_Module *loaded_module,
221                          Elf32_Addr    *sym_value)
223    int i = 0;
224    loaded_module_ptr_Queue_Node* node;
225    LOADER_OBJECT *dHandle = (LOADER_OBJECT *)handle;
227 #if LOADER_DEBUG
228    if (debugging_on)
229       DLIF_trace("DLSYM_global_lookup: %s\n", sym_name);
230 #endif
232    /*------------------------------------------------------------------------*/
233    /* We will choose a different lookup algorithm based on what kind of      */
234    /* platform we are supporting.  In the Braveheart case, the global symbol */
235    /* lookup algorithm searches the base image first, followed by the        */
236    /* explicit children of the specified Module.                             */
237    /*------------------------------------------------------------------------*/
238    if (loaded_module->direct_dependent_only)
239    {
240       int* child_handle = (int*)(loaded_module->dependencies.buf);
242       /*---------------------------------------------------------------------*/
243       /* Spin through list of this Module's dependencies (anything on its    */
244       /* DT_NEEDED list), searching through each dependent's symbol table    */
245       /* to find the symbol we are after.                                    */
246       /*---------------------------------------------------------------------*/
247       for (i = 0; i < loaded_module->dependencies.size; i++)
248       {
249          for (node = dHandle->DLIMP_loaded_objects.front_ptr;
250            node->value->file_handle != child_handle[i];
251            node=node->next_ptr);
253          /*------------------------------------------------------------------*/
254          /* Return true if we find the symbol.                               */
255          /*------------------------------------------------------------------*/
256          if (DLSYM_lookup_global_symtab(sym_name,
257                                         node->value->gsymtab,
258                                         node->value->gsymnum,
259                                         sym_value))
260             return TRUE;
261       }
262    }
264    /*------------------------------------------------------------------------*/
265    /* In the LINUX model, we will use a breadth-first global symbol lookup   */
266    /* algorithm.  First, the application's global symbol table is searched,  */
267    /* followed by its children, followed by their children, and so on.       */
268    /* It is up to the client of this module to set the application handle.   */
269    /*------------------------------------------------------------------------*/
270    else
271    {
272       if (breadth_first_lookup(handle, sym_name, DLIMP_application_handle,
273                                sym_value))
274          return TRUE;
275    }
277    /*------------------------------------------------------------------------*/
278    /* If we got this far, then symbol was not found.                         */
279    /*------------------------------------------------------------------------*/
280    DLIF_error(DLET_SYMBOL, "Could not resolve symbol %s!\n", sym_name);
282    return FALSE;
285 /*****************************************************************************/
286 /* DLSYM_lookup_symtab() - Lookup the symbol name in the given symbol table. */
287 /*                         Symbol must have specified binding. Return the    */
288 /*                         value in sym_value and return TRUE if the lookup  */
289 /*                         succeeds.                                         */
290 /*****************************************************************************/
291 static BOOL DLSYM_lookup_symtab(const char *sym_name, struct Elf32_Sym *symtab,
292                                 Elf32_Word symnum, Elf32_Addr *sym_value,
293                                 BOOL require_local_binding)
295    Elf32_Addr sym_idx;
296    for (sym_idx = 0; sym_idx < symnum; sym_idx++)
297    {
298 #if LOADER_DEBUG
299       if (debugging_on)
300          DLIF_trace("DLSYM_lookup_symtab %s\n",
301                     (char *)symtab[sym_idx].st_name);
302 #endif
304       if ((symtab[sym_idx].st_shndx != SHN_UNDEF) &&
305           ((require_local_binding &&
306             (ELF32_ST_BIND(symtab[sym_idx].st_info) == STB_LOCAL)) ||
307            (!require_local_binding &&
308             (ELF32_ST_BIND(symtab[sym_idx].st_info) != STB_LOCAL))) &&
309           !strcmp(sym_name,(char*)(symtab[sym_idx].st_name)))
310       {
311          if (sym_value) *sym_value = symtab[sym_idx].st_value;
312          return TRUE;
314       }
315    }
316    if (sym_value) *sym_value = 0;
317    return FALSE;
320 /*****************************************************************************/
321 /* DLSYM_lookup_global_symtab() - Lookup the symbol name in the given symbol */
322 /*                               table. Symbol must have global binding.     */
323 /*                               Return the value in sym_value and return    */
324 /*                               TRUE if the lookup succeeds.                */
325 /*****************************************************************************/
326 BOOL DLSYM_lookup_global_symtab(const char *sym_name, struct Elf32_Sym *symtab,
327                                 Elf32_Word symnum, Elf32_Addr *sym_value)
329    return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, FALSE);
332 /*****************************************************************************/
333 /* DLSYM_lookup_local_symtab() - Lookup the symbol name in the given symbol  */
334 /*                               table. Symbol must have local binding.      */
335 /*                               Return the value in sym_value and return    */
336 /*                               TRUE if the lookup succeeds.                */
337 /*****************************************************************************/
338 BOOL DLSYM_lookup_local_symtab(const char *sym_name, struct Elf32_Sym *symtab,
339                                Elf32_Word symnum, Elf32_Addr *sym_value)
341    return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, TRUE);
344 /*****************************************************************************/
345 /* CANONICAL_SYMBOL_LOOKUP() - Find the symbol definition. Look up the local */
346 /*                             symbol table to find the symbol. If it is a   */
347 /*                             definition and cannot be pre-empted, return   */
348 /*                             it. Otherwise, do a look up in the global     */
349 /*                             symbol table that contains the symbol tables  */
350 /*                             from all the necessary modules.               */
351 /*****************************************************************************/
352 BOOL DLSYM_canonical_lookup(DLOAD_HANDLE handle,
353                             int sym_index,
354                             DLIMP_Dynamic_Module *dyn_module,
355                             Elf32_Addr *sym_value)
357    /*------------------------------------------------------------------------*/
358    /* Lookup the symbol table to get the symbol characteristics.             */
359    /*------------------------------------------------------------------------*/
360    struct Elf32_Sym *sym = &dyn_module->symtab[sym_index];
361    int32_t           st_bind = ELF32_ST_BIND(sym->st_info);
362    int32_t           st_vis  = ELF32_ST_VISIBILITY(sym->st_other);
363    BOOL              is_def  = (sym->st_shndx != SHN_UNDEF &&
364                                (sym->st_shndx < SHN_LORESERVE ||
365                                sym->st_shndx == SHN_XINDEX));
366    const char *sym_name = (char *)sym->st_name;
368 #if LOADER_DEBUG
369    if (debugging_on)
370       DLIF_trace("DLSYM_canonical_lookup: %d, %s\n", sym_index, sym_name);
371 #endif
373    /*------------------------------------------------------------------------*/
374    /* Local symbols and symbol definitions that cannot be pre-empted         */
375    /* are resolved by the definition in the same module.                     */
376    /*------------------------------------------------------------------------*/
377    if (st_bind == STB_LOCAL || st_vis != STV_DEFAULT)
378    {
379       /*---------------------------------------------------------------------*/
380       /* If it is a local symbol or non-local that cannot be preempted,      */
381       /* the definition should be found in the same module. If we don't      */
382       /* find the definition it is an error.                                 */
383       /*---------------------------------------------------------------------*/
384       if (!is_def)
385       {
386          DLIF_error(DLET_SYMBOL,
387                     "Local/non-imported symbol %s definition is not found "
388                     "in module %s!\n", sym_name, dyn_module->name);
389          return FALSE;
390       }
391       else
392       {
393          if (sym_value) *sym_value = sym->st_value;
394          return TRUE;
395       }
396    }
397    /*------------------------------------------------------------------------*/
398    /* Else we have either pre-emptable defintion or undef symbol. We need    */
399    /* to do global look up.                                                  */
400    /*------------------------------------------------------------------------*/
401    else
402    {
403       return DLSYM_global_lookup(handle, sym_name, dyn_module->loaded_module,
404                                  sym_value);
405    }