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