00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
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
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
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