symtab.c

00001 /*
00002  * Copyright (c) 2010 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <fcntl.h>
00044 
00045 #include <elf.h>
00046 #include "include/symtab.h"
00047 
00048 static int elf_hdr_check(elf_header_t *hdr);
00049 static int section_hdr_load(int fd, const elf_header_t *ehdr, int idx,
00050     elf_section_header_t *shdr);
00051 static int chunk_load(int fd, off64_t start, size_t size, void **ptr);
00052 static int read_all(int fd, void *buf, size_t len);
00053 
00062 int symtab_load(const char *file_name, symtab_t **symtab)
00063 {
00064         symtab_t *stab;
00065         elf_header_t elf_hdr;
00066         elf_section_header_t sec_hdr;
00067         off64_t shstrt_start;
00068         size_t shstrt_size;
00069         char *shstrt, *sec_name;
00070         void *data;
00071 
00072         int fd;
00073         int rc;
00074         int i;
00075 
00076         bool load_sec, sec_is_symtab;
00077 
00078         *symtab = NULL;
00079 
00080         stab = calloc(1, sizeof(symtab_t));
00081         if (stab == NULL)
00082                 return ENOMEM;
00083 
00084         fd = open(file_name, O_RDONLY);
00085         if (fd < 0) {
00086                 printf("failed opening file\n");
00087                 free(stab);
00088                 return ENOENT;
00089         }
00090 
00091         rc = read_all(fd, &elf_hdr, sizeof(elf_header_t));
00092         if (rc != EOK) {
00093                 printf("failed reading elf header\n");
00094                 free(stab);
00095                 return EIO;
00096         }
00097 
00098         rc = elf_hdr_check(&elf_hdr);
00099         if (rc != EOK) {
00100                 printf("failed header check\n");
00101                 free(stab);
00102                 return ENOTSUP;
00103         }
00104 
00105         /*
00106          * Load section header string table.
00107          */
00108 
00109         rc = section_hdr_load(fd, &elf_hdr, elf_hdr.e_shstrndx, &sec_hdr);
00110         if (rc != EOK) {
00111                 printf("failed reading shstrt header\n");
00112                 free(stab);
00113                 return ENOTSUP;
00114         }
00115 
00116         shstrt_start = sec_hdr.sh_offset;
00117         shstrt_size = sec_hdr.sh_size;
00118 
00119         rc = chunk_load(fd, shstrt_start, shstrt_size, (void **) &shstrt);
00120         if (rc != EOK) {
00121                 printf("failed loading shstrt\n");
00122                 free(stab);
00123                 return ENOTSUP;
00124         }
00125 
00126         /* Read all section headers. */
00127         for (i = 0; i < elf_hdr.e_shnum; ++i) {
00128                 rc = section_hdr_load(fd, &elf_hdr, i, &sec_hdr);
00129                 if (rc != EOK) {
00130                         free(shstrt);
00131                         free(stab);
00132                         return ENOTSUP;
00133                 }
00134 
00135                 sec_name = shstrt + sec_hdr.sh_name;
00136                 if (str_cmp(sec_name, ".symtab") == 0 &&
00137                     sec_hdr.sh_type == SHT_SYMTAB) {
00138                         load_sec = true;
00139                         sec_is_symtab = true;
00140                 } else if (str_cmp(sec_name, ".strtab") == 0 &&
00141                     sec_hdr.sh_type == SHT_STRTAB) {
00142                         load_sec = true;
00143                         sec_is_symtab = false;
00144                 } else {
00145                         load_sec = false;
00146                 }
00147 
00148                 if (load_sec) {
00149                         rc = chunk_load(fd, sec_hdr.sh_offset, sec_hdr.sh_size,
00150                             &data);
00151                         if (rc != EOK) {
00152                                 free(shstrt);
00153                                 free(stab);
00154                                 return ENOTSUP;
00155                         }
00156 
00157                         if (sec_is_symtab) {
00158                                 stab->sym = data;
00159                                 stab->sym_size = sec_hdr.sh_size;
00160                         } else {
00161                                 stab->strtab = data;
00162                                 stab->strtab_size = sec_hdr.sh_size;
00163                         }
00164                 }
00165         }
00166 
00167         free(shstrt);
00168         close(fd);
00169 
00170         if (stab->sym == NULL || stab->strtab == NULL) {
00171                 /* Tables not found. */
00172                 printf("Symbol table or string table section not found\n");
00173                 free(stab);
00174                 return ENOTSUP;
00175         }
00176 
00177         *symtab = stab;
00178 
00179         return EOK;
00180 }
00181 
00186 void symtab_delete(symtab_t *st)
00187 {
00188         free(st->sym);
00189         st->sym = NULL;
00190 
00191         free(st->strtab);
00192         st->strtab = NULL;
00193 
00194         free(st);
00195 }
00196 
00205 int symtab_name_to_addr(symtab_t *st, char *name, uintptr_t *addr)
00206 {
00207         size_t i;
00208         char *sname;
00209         unsigned stype;
00210 
00211         for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
00212                 if (st->sym[i].st_name == 0)
00213                         continue;
00214 
00215                 stype = ELF_ST_TYPE(st->sym[i].st_info);
00216                 if (stype != STT_OBJECT && stype != STT_FUNC)
00217                         continue;
00218 
00219                 sname = st->strtab + st->sym[i].st_name;
00220 
00221                 if (str_cmp(sname, name) == 0) {
00222                         *addr = st->sym[i].st_value;
00223                         return EOK;
00224                 }
00225         }
00226 
00227         return ENOENT;
00228 }
00229 
00242 int symtab_addr_to_name(symtab_t *st, uintptr_t addr, char **name,
00243     size_t *offs)
00244 {
00245         size_t i;
00246         uintptr_t saddr, best_addr;
00247         char *sname, *best_name;
00248         unsigned stype;
00249 
00250         best_name = NULL;
00251         best_addr = 0;
00252 
00253         for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
00254                 if (st->sym[i].st_name == 0)
00255                         continue;
00256 
00257                 stype = ELF_ST_TYPE(st->sym[i].st_info);
00258                 if (stype != STT_OBJECT && stype != STT_FUNC &&
00259                     stype != STT_NOTYPE) {
00260                         continue;
00261                 }
00262 
00263                 saddr = st->sym[i].st_value;
00264                 sname = st->strtab + st->sym[i].st_name;
00265 
00266                 /* An ugly hack to filter out some special ARM symbols. */
00267                 if (sname[0] == '$')
00268                         continue;
00269 
00270                 if (best_name == NULL || (saddr <= addr && saddr > best_addr)) {
00271                         best_name = sname;
00272                         best_addr = saddr;
00273                 }
00274         }
00275 
00276         if (best_name == NULL)
00277                 return ENOENT;
00278 
00279         *name = best_name;
00280         *offs = addr - best_addr;
00281         return EOK;
00282 }
00283 
00288 static int elf_hdr_check(elf_header_t *ehdr)
00289 {
00290         /* TODO */
00291         return EOK;
00292 }
00293 
00303 static int section_hdr_load(int fd, const elf_header_t *elf_hdr, int idx,
00304     elf_section_header_t *sec_hdr)
00305 {
00306         int rc;
00307 
00308         rc = lseek(fd, elf_hdr->e_shoff + idx * sizeof(elf_section_header_t),
00309             SEEK_SET);
00310         if (rc == (off64_t) -1)
00311                 return EIO;
00312 
00313         rc = read_all(fd, sec_hdr, sizeof(elf_section_header_t));
00314         if (rc != EOK)
00315                 return EIO;
00316 
00317         return EOK;
00318 }
00319 
00331 static int chunk_load(int fd, off64_t start, size_t size, void **ptr)
00332 {
00333         int rc;
00334 
00335         rc = lseek(fd, start, SEEK_SET);
00336         if (rc == (off64_t) -1) {
00337                 printf("failed seeking chunk\n");
00338                 *ptr = NULL;
00339                 return EIO;
00340         }
00341 
00342         *ptr = malloc(size);
00343         if (*ptr == NULL) {
00344                 printf("failed allocating memory\n");
00345                 return ENOMEM;
00346         }
00347 
00348         rc = read_all(fd, *ptr, size);
00349         if (rc != EOK) {
00350                 printf("failed reading chunk\n");
00351                 free(*ptr);
00352                 *ptr = NULL;
00353                 return EIO;
00354         }
00355 
00356         return EOK;
00357 }
00358 
00370 static int read_all(int fd, void *buf, size_t len)
00371 {
00372         int cnt = 0;
00373 
00374         do {
00375                 buf += cnt;
00376                 len -= cnt;
00377                 cnt = read(fd, buf, len);
00378         } while (cnt > 0 && (len - cnt) > 0);
00379 
00380         if (cnt < 0)
00381                 return cnt;
00382 
00383         if (len - cnt > 0)
00384                 return EIO;
00385 
00386         return EOK;
00387 }
00388 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7