]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/ia64/libuwx/src/uwx_symbols.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / ia64 / libuwx / src / uwx_symbols.c
1 /*
2 Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
10 conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #ifdef USE_CLEAN_NAMESPACE
26 #define fopen _fopen
27 #define fseek _fseek
28 #define fread _fread
29 #define fclose _fclose
30 #endif /* USE_CLEAN_NAMESPACE */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <inttypes.h>
36 #include <elf.h>
37
38 #include "uwx.h"
39 #include "uwx_env.h"
40
41 #ifdef USE_CLEAN_NAMESPACE
42 /*
43  * Moved the defines above the include of stdio.h,
44  * so we don't need these unless that causes problems
45  * and we have to move them back down here.
46  * #define fopen _fopen
47  * #define fseek _fseek
48  * #define fread _fread
49  * #define fclose _fclose
50  * extern FILE *_fopen(const char *, const char *);
51  * extern int _fseek(FILE *, long int, int);
52  * extern size_t _fread(void *, size_t, size_t, FILE *);
53  * extern int _fclose(FILE *);
54  */
55 #endif /* USE_CLEAN_NAMESPACE */
56
57 struct uwx_symbol_cache {
58     char *module_name;
59     int nsyms;
60     uint64_t *sym_values;
61     char **sym_names;
62     char *strings;
63 };
64
65
66 int uwx_read_func_symbols(
67     struct uwx_env *env,
68     struct uwx_symbol_cache *cache,
69     char *module_name);
70
71
72 int uwx_find_symbol(
73     struct uwx_env *env,
74     struct uwx_symbol_cache **symbol_cache_p,
75     char *module_name,
76     uint64_t relip,
77     char **func_name_p,
78     uint64_t *offset_p)
79 {
80     int status;
81     int i;
82     uint64_t offset;
83     uint64_t best_offset;
84     char *best_name;
85     struct symbol *sym;
86     struct uwx_symbol_cache *cache = NULL;
87
88     /* Allocate a symbol cache on first call */
89     if (symbol_cache_p != NULL)
90         cache = *symbol_cache_p;
91     if (cache == NULL) {
92         cache = (struct uwx_symbol_cache *)
93                         (*env->allocate_cb)(sizeof(struct uwx_symbol_cache));
94         if (cache == NULL)
95             return UWX_ERR_NOMEM;
96         cache->module_name = NULL;
97         cache->nsyms = 0;
98         cache->sym_values = NULL;
99         cache->sym_names = NULL;
100         cache->strings = NULL;
101         if (symbol_cache_p != NULL)
102             *symbol_cache_p = cache;
103     }
104
105     /* Read function symbols from the object file */
106     status = uwx_read_func_symbols(env, cache, module_name);
107     if (status != UWX_OK)
108         return status;
109
110     /* Search for best match */
111     best_offset = ~(uint64_t)0;
112     best_name = NULL;
113     for (i = 0; i < cache->nsyms; i++) {
114         if (cache->sym_values[i] == relip) {
115             *func_name_p = cache->sym_names[i];
116             *offset_p = 0;
117             if (symbol_cache_p == NULL)
118                 uwx_release_symbol_cache(env, cache);
119             return UWX_OK;
120         }
121         if (relip > cache->sym_values[i]) {
122             offset = relip - cache->sym_values[i];
123             if (offset < best_offset) {
124                 best_offset = offset;
125                 best_name = cache->sym_names[i];
126             }
127         }
128     }
129     if (best_name == NULL)
130         return UWX_ERR_NOSYM;
131
132     if (symbol_cache_p == NULL)
133         uwx_release_symbol_cache(env, cache);
134
135     *func_name_p = best_name;
136     *offset_p = best_offset;
137     return UWX_OK;
138 }
139
140
141 void uwx_release_symbol_cache(
142     struct uwx_env *env,
143     struct uwx_symbol_cache *symbol_cache)
144 {
145     if (symbol_cache->module_name != NULL)
146         (*env->free_cb)(symbol_cache->module_name);
147     if (symbol_cache->sym_values != NULL)
148         (*env->free_cb)(symbol_cache->sym_values);
149     if (symbol_cache->sym_names != NULL)
150         (*env->free_cb)(symbol_cache->sym_names);
151     if (symbol_cache->strings != NULL)
152         (*env->free_cb)(symbol_cache->strings);
153     (*env->free_cb)(symbol_cache);
154 }
155
156
157 #define ELF_ERR_NOMEM           UWX_ERR_NOMEM  /* Out of memory */
158 #define ELF_ERR_OPEN            UWX_ERR_NOSYM  /* Can't open file */
159
160 #define ELF_ERR_NOHEADER        UWX_ERR_NOSYM  /* Can't read ELF header */
161 #define ELF_ERR_NOTELF          UWX_ERR_NOSYM  /* Not an ELF file */
162 #define ELF_ERR_HEADER_SIZE     UWX_ERR_NOSYM  /* Invalid e_ehsize */
163 #define ELF_ERR_INVALID_CLASS   UWX_ERR_NOSYM  /* Invalid EI_CLASS */
164 #define ELF_ERR_INVALID_DATA    UWX_ERR_NOSYM  /* Invalid EI_DATA */
165
166 #define ELF_ERR_READ_SECTHDR    UWX_ERR_NOSYM  /* Can't read section headers */
167 #define ELF_ERR_SECTHDR_SIZE    UWX_ERR_NOSYM  /* Invalid e_shentsize */
168
169 #define ELF_ERR_READ_PROGHDR    UWX_ERR_NOSYM  /* Can't read program headers */
170 #define ELF_ERR_PROGHDR_SIZE    UWX_ERR_NOSYM  /* Invalid e_phentsize */
171
172 #define ELF_ERR_READ_SECTION    UWX_ERR_NOSYM  /* Can't read section contents */
173
174 #define ELF_ERR_READ_SYMTAB     UWX_ERR_NOSYM  /* Can't read symbol table */
175 #define ELF_ERR_SYMTAB_SIZE     UWX_ERR_NOSYM  /* Invalid sh_entsize for symtab */
176
177
178 struct elf_file {
179     uint64_t phoff;
180     uint64_t shoff;
181     uint64_t text_base;
182     uint64_t text_end;
183     alloc_cb allocate_cb;
184     free_cb free_cb;
185     const char *filename;
186     FILE *fd;
187     struct elf_section *sections;
188     struct elf_symbol *symbols;
189     char *symbol_strings;
190     int native_data;
191     int source_class;
192     int source_data;
193     int ehsize;
194     int phentsize;
195     int phnum;
196     int shentsize;
197     int shnum;
198     int nsyms;
199 };
200
201 struct elf_section {
202     uint64_t flags;
203     uint64_t addr;
204     uint64_t offset;
205     uint64_t size;
206     uint64_t entsize;
207     char *contents;
208     struct elf_symbol *symbols;
209     int type;
210     int link;
211     int info;
212     int nelems;
213 };
214
215 struct elf_symbol {
216     uint64_t value;
217     char *namep;
218     int name;
219     int type;
220     int shndx;
221 };
222
223
224 static void elf_swap_bytes(char *buf, char *template)
225 {
226     int i;
227     int sz;
228     char temp[16];
229
230     while (sz = *template++) {
231         if (sz > 16)
232             exit(1);
233         for (i = 0; i < sz; i++)
234             temp[i] = buf[i];
235         for (i = 0; i < sz; i++)
236             buf[i] = temp[sz-i-1];
237         buf += sz;
238     }
239 }
240
241
242 static int elf_read_section(struct elf_file *ef, int shndx)
243 {
244     struct elf_section *sect;
245
246     if (shndx < 0 || shndx > ef->shnum)
247         return 0;
248
249     sect = &ef->sections[shndx];
250
251     /* Return if section has already been read */
252     if (sect->contents != NULL)
253         return 0;
254
255     sect->contents = (*ef->allocate_cb)(sect->size);
256     if (sect->contents == NULL)
257         return ELF_ERR_NOMEM;
258
259     fseek(ef->fd, (long)sect->offset, SEEK_SET);
260     if (fread(sect->contents, 1, sect->size, ef->fd) != sect->size)
261         return ELF_ERR_READ_SECTION;
262
263     return 0;
264 }
265
266
267 static char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0};
268 static char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0};
269
270 static int elf_read_symtab_section(struct elf_file *ef, int shndx)
271 {
272     int i;
273     int nsyms;
274     long size;
275     union {
276         Elf32_Sym sym32;
277         Elf64_Sym sym64;
278     } sym;
279     struct elf_section *sect;
280     struct elf_symbol *syms;
281     struct elf_symbol *symp;
282     char *strtab;
283
284     sect = &ef->sections[shndx];
285
286     /* Return if section has already been read */
287     if (sect->symbols != NULL)
288         return 0;
289
290     if (ef->source_class == ELFCLASS32) {
291         if (sect->entsize != sizeof(sym.sym32))
292             return ELF_ERR_SYMTAB_SIZE;
293     }
294     else {
295         if (sect->entsize != sizeof(sym.sym64))
296             return ELF_ERR_SYMTAB_SIZE;
297     }
298
299     nsyms = sect->nelems;
300     syms = (struct elf_symbol *)
301                         (*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms);
302     if (syms == NULL)
303         return ELF_ERR_NOMEM;
304
305     /* Read the symbol table */
306     fseek(ef->fd, (long)sect->offset, SEEK_SET);
307     for (i = 0; i < nsyms; i++) {
308
309         symp = &syms[i];
310
311         /* Read the next symbol table entry */
312         if (fread((char *)&sym, sect->entsize, 1, ef->fd) != 1) {
313             (*ef->free_cb)(syms);
314             return ELF_ERR_READ_SYMTAB;
315         }
316
317         /* Get fields from appropriate structure */
318         if (ef->source_class == ELFCLASS32) {
319             /* Swap bytes if necessary */
320             if (ef->source_data != ef->native_data)
321                 elf_swap_bytes((char *)&sym, template_elf32_sym);
322             symp->name = sym.sym32.st_name;
323             symp->type = sym.sym32.st_info & 0x0f;
324             symp->shndx = sym.sym32.st_shndx;
325             symp->value = sym.sym32.st_value;
326         }
327         else {
328             /* Swap bytes if necessary */
329             if (ef->source_data != ef->native_data)
330                 elf_swap_bytes((char *)&sym, template_elf64_sym);
331             symp->name = sym.sym64.st_name;
332             symp->type = sym.sym64.st_info & 0x0f;
333             symp->shndx = sym.sym64.st_shndx;
334             symp->value = sym.sym64.st_value;
335         }
336         symp->namep = NULL;
337
338     }
339
340     /* Read the symbol string table and convert section names */
341     /* from string table offsets to pointers */
342     if (sect->link > 0 && sect->link < ef->shnum) {
343         if (elf_read_section(ef, sect->link) == 0) {
344             strtab = ef->sections[sect->link].contents;
345             for (i = 0; i < nsyms; i++) {
346                 symp = &syms[i];
347                 symp->namep = strtab + symp->name;
348             }
349             ef->symbol_strings = strtab;
350             ef->sections[sect->link].contents = NULL;
351         }
352     }
353
354     sect->symbols = syms;
355     return 0;
356 }
357
358
359 static char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0};
360 static char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0};
361
362 static int elf_read_prog_hdrs(struct elf_file *ef)
363 {
364     int i;
365     union {
366         Elf32_Phdr hdr32;
367         Elf64_Phdr hdr64;
368     } header;
369     uint64_t vaddr;
370     uint64_t memsz;
371     uint64_t unwind_base;
372     int type;
373
374     if (ef->phnum == 0)
375         return 0;
376
377     if (ef->source_class == ELFCLASS32) {
378         if (ef->phentsize != sizeof(header.hdr32))
379             return ELF_ERR_PROGHDR_SIZE;
380     }
381     else {
382         if (ef->phentsize != sizeof(header.hdr64))
383             return ELF_ERR_PROGHDR_SIZE;
384     }
385
386     /* Look for the PT_IA_64_UNWIND segment */
387     /* (That will help us identify the text segment) */
388
389     fseek(ef->fd, (long)ef->phoff, SEEK_SET);
390     for (i = 0; i < ef->phnum; i++) {
391
392         /* Read the next program header */
393         if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
394             return ELF_ERR_READ_PROGHDR;
395
396         /* Get fields from appropriate structure */
397         if (ef->source_class == ELFCLASS32) {
398             /* Swap bytes in header fields if necessary */
399             if (ef->source_data != ef->native_data)
400                 elf_swap_bytes((char *)&header, template_elf32_phdr);
401             type = header.hdr32.p_type;
402             vaddr = header.hdr32.p_vaddr;
403         }
404         else {
405             /* Swap bytes in header fields if necessary */
406             if (ef->source_data != ef->native_data)
407                 elf_swap_bytes((char *)&header, template_elf64_phdr);
408             type = header.hdr64.p_type;
409             vaddr = header.hdr64.p_vaddr;
410         }
411
412         if (type == PT_IA_64_UNWIND) {
413             unwind_base = vaddr;
414             break;
415         }
416
417     }
418
419     /* Now look for the PT_LOAD segment that includes the unwind segment */
420
421     fseek(ef->fd, (long)ef->phoff, SEEK_SET);
422     for (i = 0; i < ef->phnum; i++) {
423
424         /* Read the next program header */
425         if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
426             return ELF_ERR_READ_PROGHDR;
427
428         /* Get fields from appropriate structure */
429         if (ef->source_class == ELFCLASS32) {
430             /* Swap bytes in header fields if necessary */
431             if (ef->source_data != ef->native_data)
432                 elf_swap_bytes((char *)&header, template_elf32_phdr);
433             type = header.hdr32.p_type;
434             vaddr = header.hdr32.p_vaddr;
435             memsz = header.hdr32.p_memsz;
436         }
437         else {
438             /* Swap bytes in header fields if necessary */
439             if (ef->source_data != ef->native_data)
440                 elf_swap_bytes((char *)&header, template_elf64_phdr);
441             type = header.hdr64.p_type;
442             vaddr = header.hdr64.p_vaddr;
443             memsz = header.hdr64.p_memsz;
444         }
445
446         if (type == PT_LOAD &&
447                 vaddr <= unwind_base && unwind_base < vaddr + memsz) {
448             ef->text_base = vaddr;
449             ef->text_end = vaddr + memsz;
450             break;
451         }
452
453     }
454
455     return 0;
456 }
457
458
459 static char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0};
460 static char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0};
461
462 static int elf_read_sect_hdrs(struct elf_file *ef)
463 {
464     int i;
465     long size;
466     int err;
467     union {
468         Elf32_Shdr hdr32;
469         Elf64_Shdr hdr64;
470     } header;
471     struct elf_section *sect;
472     char *shstrtab;
473
474     if (ef->source_class == ELFCLASS32) {
475         if (ef->shentsize != sizeof(header.hdr32))
476             return ELF_ERR_SECTHDR_SIZE;
477     }
478     else {
479         if (ef->shentsize != sizeof(header.hdr64))
480             return ELF_ERR_SECTHDR_SIZE;
481     }
482
483     fseek(ef->fd, (long)ef->shoff, SEEK_SET);
484     ef->sections = (struct elf_section *)
485                     (*ef->allocate_cb)(sizeof(struct elf_section) * ef->shnum);
486     if (ef->sections == NULL)
487         return ELF_ERR_NOMEM;
488
489     /* Read the section header table */
490     for (i = 0; i < ef->shnum; i++) {
491
492         sect = &ef->sections[i];
493
494         /* Read the next section header */
495         if (fread((char *)&header, ef->shentsize, 1, ef->fd) != 1) {
496             (*ef->free_cb)(ef->sections);
497             return ELF_ERR_READ_SECTHDR;
498         }
499
500         /* Get fields from appropriate structure */
501         if (ef->source_class == ELFCLASS32) {
502             /* Swap bytes in header fields if necessary */
503             if (ef->source_data != ef->native_data)
504                 elf_swap_bytes((char *)&header, template_elf32_shdr);
505             sect->type = header.hdr32.sh_type;
506             sect->flags = header.hdr32.sh_flags;
507             sect->addr = header.hdr32.sh_addr;
508             sect->offset = header.hdr32.sh_offset;
509             sect->size = header.hdr32.sh_size;
510             sect->link = header.hdr32.sh_link;
511             sect->info = header.hdr32.sh_info;
512             sect->entsize = header.hdr32.sh_entsize;
513         }
514         else {
515             /* Swap bytes in header fields if necessary */
516             if (ef->source_data != ef->native_data)
517                 elf_swap_bytes((char *)&header, template_elf64_shdr);
518             sect->type = header.hdr64.sh_type;
519             sect->flags = header.hdr64.sh_flags;
520             sect->addr = header.hdr64.sh_addr;
521             sect->offset = header.hdr64.sh_offset;
522             sect->size = header.hdr64.sh_size;
523             sect->link = header.hdr64.sh_link;
524             sect->info = header.hdr64.sh_info;
525             sect->entsize = header.hdr64.sh_entsize;
526         }
527         sect->contents = NULL;
528         sect->symbols = NULL;
529         if (sect->entsize > 0)
530             sect->nelems = sect->size / sect->entsize;
531
532     }
533
534     return 0;
535 }
536
537
538 static char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0};
539 static char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0};
540
541 static int elf_read_header(struct elf_file *ef)
542 {
543     union {
544         char ident[EI_NIDENT];
545         Elf32_Ehdr hdr32;
546         Elf64_Ehdr hdr64;
547     } header;
548
549     /* Read the ELF header */
550     fseek(ef->fd, 0L, SEEK_SET);
551     if (fread((char *)header.ident, EI_NIDENT, 1, ef->fd) != 1) {
552         return ELF_ERR_NOHEADER;
553     }
554
555     /* Verify that this is an ELF file */
556     if (header.ident[EI_MAG0] != ELFMAG0 ||
557         header.ident[EI_MAG1] != ELFMAG1 ||
558         header.ident[EI_MAG2] != ELFMAG2 ||
559         header.ident[EI_MAG3] != ELFMAG3) {
560         return ELF_ERR_NOTELF;
561     }
562
563     /* Get header fields from the byte array e_ident */
564     /* (These are independent of EI_CLASS and EI_DATA) */
565     ef->source_class = header.ident[EI_CLASS];
566     ef->source_data = header.ident[EI_DATA];
567
568     /* Verify EI_CLASS and EI_DATA */
569     if (header.ident[EI_CLASS] != ELFCLASS32 &&
570         header.ident[EI_CLASS] != ELFCLASS64) {
571         return ELF_ERR_INVALID_CLASS;
572     }
573     if (header.ident[EI_DATA] != ELFDATA2LSB &&
574         header.ident[EI_DATA] != ELFDATA2MSB) {
575         return ELF_ERR_INVALID_DATA;
576     }
577
578     /* Get remaining header fields from appropriate structure */
579     if (ef->source_class == ELFCLASS32) {
580         if (fread((char *)&header.hdr32 + EI_NIDENT,
581                         sizeof(header.hdr32) - EI_NIDENT, 1, ef->fd) != 1)
582             return ELF_ERR_NOHEADER;
583         /* Swap bytes in header fields if necessary */
584         if (ef->source_data != ef->native_data)
585             elf_swap_bytes((char *)&header + EI_NIDENT, template_elf32_ehdr);
586         ef->phoff = header.hdr32.e_phoff;
587         ef->shoff = header.hdr32.e_shoff;
588         ef->ehsize = header.hdr32.e_ehsize;
589         ef->phentsize = header.hdr32.e_phentsize;
590         ef->phnum = header.hdr32.e_phnum;
591         ef->shentsize = header.hdr32.e_shentsize;
592         ef->shnum = header.hdr32.e_shnum;
593         if (ef->ehsize != sizeof(header.hdr32)) {
594             return ELF_ERR_HEADER_SIZE;
595         }
596     }
597     else {
598         if (fread((char *)&header.hdr64 + EI_NIDENT,
599                         sizeof(header.hdr64) - EI_NIDENT, 1, ef->fd) != 1)
600             return ELF_ERR_NOHEADER;
601         /* Swap bytes in header fields if necessary */
602         if (ef->source_data != ef->native_data)
603             elf_swap_bytes((char *)&header + EI_NIDENT, template_elf64_ehdr);
604         ef->phoff = header.hdr64.e_phoff;
605         ef->shoff = header.hdr64.e_shoff;
606         ef->ehsize = header.hdr64.e_ehsize;
607         ef->phentsize = header.hdr64.e_phentsize;
608         ef->phnum = header.hdr64.e_phnum;
609         ef->shentsize = header.hdr64.e_shentsize;
610         ef->shnum = header.hdr64.e_shnum;
611         if (ef->ehsize != sizeof(header.hdr64)) {
612             return ELF_ERR_HEADER_SIZE;
613         }
614     }
615
616     return 0;
617 }
618
619
620 static struct elf_file *elf_new(struct uwx_env *env)
621 {
622     int native_be;
623     char *p;
624     struct elf_file *ef;
625
626     ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file));
627     if (ef == NULL)
628         return NULL;
629
630     /* Determine the native byte order */
631     p = (char *)&native_be;
632     native_be = 1;      /* Assume big-endian */
633     *p = 0;             /* Sets be == 0 only if little-endian */
634
635     ef->allocate_cb = env->allocate_cb;
636     ef->free_cb = env->free_cb;
637     ef->filename = NULL;
638     ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB);
639     ef->fd = NULL;
640     ef->source_class = 0;
641     ef->source_data = 0;
642     ef->phoff = 0;
643     ef->shoff = 0;
644     ef->text_base = 0;
645     ef->text_end = 0;
646     ef->ehsize = 0;
647     ef->phentsize = 0;
648     ef->phnum = 0;
649     ef->shentsize = 0;
650     ef->shnum = 0;
651     ef->sections = NULL;
652     ef->symbols = NULL;
653     ef->symbol_strings = NULL;
654     ef->nsyms = 0;
655     return ef;
656 }
657
658
659 static int elf_open(struct elf_file *ef, const char *filename)
660 {
661     int err;
662
663     ef->filename = filename;
664
665     ef->fd = fopen(filename, "r");
666     if (ef->fd == NULL)
667         return ELF_ERR_OPEN;
668
669     if ((err = elf_read_header(ef)) != 0)
670         return err;
671
672     if ((err = elf_read_sect_hdrs(ef)) != 0)
673         return err;
674
675     if ((err = elf_read_prog_hdrs(ef)) != 0)
676         return err;
677
678     return 0;
679 }
680
681
682 static void elf_free_sections(struct elf_file *ef)
683 {
684     int i;
685     struct elf_section *sect;
686
687     for (i = 0; i < ef->shnum; i++) {
688         sect = &ef->sections[i];
689         if (sect->contents != NULL)
690             (*ef->free_cb)(sect->contents);
691         if ((sect->type == SHT_SYMTAB || sect->type == SHT_DYNSYM)
692                                                 && sect->symbols != NULL)
693             (*ef->free_cb)(sect->symbols);
694     }
695     (*ef->free_cb)(ef->sections);
696 }
697
698
699 static void elf_close(struct elf_file *ef)
700 {
701     if (ef->fd != NULL) {
702         fclose(ef->fd);
703         ef->fd = NULL;
704     }
705 }
706
707
708 static void elf_free(struct elf_file *ef)
709 {
710     elf_close(ef);
711     if (ef->sections != NULL)
712         elf_free_sections(ef);
713     (*ef->free_cb)(ef);
714 }
715
716
717 static int elf_read_symbols(struct elf_file *ef)
718 {
719     int i;
720     int err;
721     struct elf_section *sect;
722
723     for (i = 1; i < ef->shnum; i++) {
724         sect = &ef->sections[i];
725         if (sect->type == SHT_SYMTAB) {
726             if (elf_read_symtab_section(ef, i) == 0) {
727                 ef->symbols = sect->symbols;
728                 ef->nsyms = sect->nelems;
729 #ifdef DEBUG_SYMBOLS
730                 printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms);
731 #endif /* DEBUG_SYMBOLS */
732                 return 0;
733             }
734         }
735     }
736     for (i = 1; i < ef->shnum; i++) {
737         sect = &ef->sections[i];
738         if (sect->type == SHT_DYNSYM) {
739             if (elf_read_symtab_section(ef, i) == 0) {
740                 ef->symbols = sect->symbols;
741                 ef->nsyms = sect->nelems;
742 #ifdef DEBUG_SYMBOLS
743                 printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms);
744 #endif /* DEBUG_SYMBOLS */
745                 return 0;
746             }
747         }
748     }
749     return UWX_ERR_NOSYM;
750 }
751
752
753 #define SYM_IS_DEFINED(sym) \
754                 ((sym)->shndx != SHN_UNDEF)
755
756 #define SYM_IS_IN_TEXT_SEGMENT(value) \
757                 ((value) >= ef->text_base && (value) < ef->text_end)
758
759 #define SYM_HAS_INTERESTING_TYPE(type) ( \
760                 (type) == STT_FUNC || \
761                 (type) == STT_OBJECT || \
762                 (type) == STT_HP_STUB \
763                 )
764
765 #define SYM_IS_INTERESTING(sym) ( \
766                 SYM_IS_DEFINED(sym) && \
767                 SYM_IS_IN_TEXT_SEGMENT((sym)->value) && \
768                 SYM_HAS_INTERESTING_TYPE((sym)->type) \
769                 )
770
771 int uwx_read_func_symbols(
772     struct uwx_env *env,
773     struct uwx_symbol_cache *cache,
774     char *module_name)
775 {
776     int i, j;
777     int status;
778     struct elf_file *ef;
779     struct elf_symbol *sym;
780     int nfuncsyms;
781     char **names;
782     uint64_t *values;
783
784     if (module_name != NULL &&
785             cache->module_name != NULL &&
786                 strcmp(module_name, cache->module_name) == 0)
787         return UWX_OK;
788
789     if (cache->sym_names != NULL)
790         (*env->free_cb)(cache->sym_names);
791     if (cache->sym_values != NULL)
792         (*env->free_cb)(cache->sym_values);
793     if (cache->strings != NULL)
794         (*env->free_cb)(cache->strings);
795
796     ef = elf_new(env);
797     if (ef == NULL)
798         return UWX_ERR_NOMEM;
799     status = elf_open(ef, module_name);
800     if (status != 0)
801         return UWX_ERR_NOSYM;
802     status = elf_read_symbols(ef);
803     if (status != 0)
804         return UWX_ERR_NOSYM;
805
806     nfuncsyms = 0;
807     for (i = 0; i < ef->nsyms; i++) {
808         sym = &ef->symbols[i];
809         if (SYM_IS_INTERESTING(sym))
810             nfuncsyms++;
811     }
812
813     names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *));
814     if (names == NULL)
815         return UWX_ERR_NOMEM;
816     values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t));
817     if (values == NULL)
818         return UWX_ERR_NOMEM;
819
820     j = 0;
821     for (i = 0; i < ef->nsyms; i++) {
822         sym = &ef->symbols[i];
823         if (SYM_IS_INTERESTING(sym)) {
824             if (j >= nfuncsyms) /* should not happen! */
825                 break;
826             names[j] = sym->namep;
827             values[j] = sym->value - ef->text_base;
828             j++;
829         }
830     }
831
832     cache->module_name = (char *)(*env->allocate_cb)(strlen(module_name)+1);
833     if (cache->module_name != NULL) {
834         strcpy(cache->module_name, module_name);
835         cache->nsyms = nfuncsyms;
836         cache->sym_names = names;
837         cache->sym_values = values;
838         cache->strings = ef->symbol_strings;
839         ef->symbol_strings = NULL;
840     }
841
842     elf_close(ef);
843     elf_free(ef);
844
845 #ifdef DEBUG_SYMBOLS
846     printf("Cached %d interesting symbols\n", nfuncsyms);
847 #endif /* DEBUG_SYMBOLS */
848
849     return UWX_OK;
850 }