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 }
144 }
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)
154 {
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;
212 }
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)
222 {
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;
283 }
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)
294 {
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;
318 }
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)
328 {
329 return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, FALSE);
330 }
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)
340 {
341 return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, TRUE);
342 }
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)
356 {
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 }
406 }