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 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 #include <sys/mman.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <fcntl.h>
00037
00038 #if CMK_HAS_ELF_H
00039 #include <elf.h>
00040
00041 #include "converse.h"
00042
00043 #if CMK_AMD64 || CMK_CRAYXT
00044 typedef Elf64_Addr ELFXX_TYPE_Addr;
00045 typedef Elf64_Dyn ELFXX_TYPE_Dyn;
00046 typedef Elf64_Rela ELFXX_TYPE_Rel;
00047 typedef Elf64_Sym ELFXX_TYPE_Sym;
00048 typedef Elf64_Shdr ELFXX_TYPE_Shdr;
00049 typedef Elf64_Ehdr ELFXX_TYPE_Ehdr;
00050 #define ELFXX_R_TYPE ELF64_R_TYPE
00051 #define ELFXX_R_SYM ELF64_R_SYM
00052 #define ELFXX_ST_TYPE ELF64_ST_TYPE
00053 #define CMK_DT_REL DT_RELA
00054 #define CMK_DT_RELSZ DT_RELASZ
00055 #define is_elf_global(x) ((x) == R_X86_64_GLOB_DAT)
00056 #elif CMK_IA64
00057 #error "NOT SUPPORTED"
00058 #else
00059 typedef Elf32_Addr ELFXX_TYPE_Addr;
00060 typedef Elf32_Dyn ELFXX_TYPE_Dyn;
00061 typedef Elf32_Rel ELFXX_TYPE_Rel;
00062 typedef Elf32_Sym ELFXX_TYPE_Sym;
00063 typedef Elf32_Shdr ELFXX_TYPE_Shdr;
00064 typedef Elf32_Ehdr ELFXX_TYPE_Ehdr;
00065 #define ELFXX_R_TYPE ELF32_R_TYPE
00066 #define ELFXX_R_SYM ELF32_R_SYM
00067 #define ELFXX_ST_TYPE ELF32_ST_TYPE
00068 #define CMK_DT_REL DT_REL
00069 #define CMK_DT_RELSZ DT_RELSZ
00070 #define is_elf_global(x) ((x) == R_386_GLOB_DAT)
00071 #endif
00072
00073
00074 typedef struct symtab *symtab_t;
00075 struct symlist {
00076 ELFXX_TYPE_Sym *sym;
00077 char *str;
00078 unsigned num;
00079 };
00080 struct symtab {
00081 struct symlist *st;
00082 struct symlist *dyn;
00083 };
00084
00085
00086
00087 #define MAX_NAME_LEN 256
00088 #define MEMORY_ONLY "[memory]"
00089 struct mm {
00090 char name[MAX_NAME_LEN];
00091 unsigned long start, end;
00092 };
00093 static struct mm mm[50];
00094 static int nmm;
00095
00096
00097 extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
00098
00099 static struct symlist *
00100 get_syms(int fd, ELFXX_TYPE_Shdr *symh, ELFXX_TYPE_Shdr *strh)
00101 {
00102 struct symlist *sl, *ret;
00103 int rv;
00104
00105 ret = NULL;
00106 sl = (struct symlist *) malloc(sizeof(struct symlist));
00107 if (!sl) {
00108 fprintf(stderr, "Out of memory\n");
00109 goto out;
00110 }
00111 sl->str = NULL;
00112 sl->sym = NULL;
00113
00114
00115 if (symh->sh_size % sizeof(ELFXX_TYPE_Sym)) {
00116 fprintf(stderr, "elf_error\n");
00117 goto out;
00118 }
00119
00120
00121 sl->num = symh->sh_size / sizeof(ELFXX_TYPE_Sym);
00122 sl->sym = (ELFXX_TYPE_Sym *) malloc(symh->sh_size);
00123 if (!sl->sym) {
00124 fprintf(stderr, "Out of memory\n");
00125 goto out;
00126 }
00127 rv = pread(fd, sl->sym, symh->sh_size, symh->sh_offset);
00128 if (0 > rv) {
00129 perror("read");
00130 goto out;
00131 }
00132 if (rv != symh->sh_size) {
00133 fprintf(stderr, "elf error\n");
00134 goto out;
00135 }
00136
00137
00138 sl->str = (char *) malloc(strh->sh_size);
00139 if (!sl->str) {
00140 fprintf(stderr, "Out of memory\n");
00141 goto out;
00142 }
00143 rv = pread(fd, sl->str, strh->sh_size, strh->sh_offset);
00144 if (0 > rv) {
00145 perror("read");
00146 goto out;
00147 }
00148 if (rv != strh->sh_size) {
00149 fprintf(stderr, "elf error");
00150 goto out;
00151 }
00152
00153 ret = sl;
00154 out:
00155 return ret;
00156 }
00157
00158 static int
00159 do_load(int fd, symtab_t symtab)
00160 {
00161 int rv;
00162 size_t size;
00163 ELFXX_TYPE_Ehdr ehdr;
00164 ELFXX_TYPE_Shdr *shdr = NULL, *p;
00165 ELFXX_TYPE_Shdr *dynsymh, *dynstrh;
00166 ELFXX_TYPE_Shdr *symh, *strh;
00167 char *shstrtab = NULL;
00168 int i;
00169 int ret = -1;
00170
00171
00172 rv = read(fd, &ehdr, sizeof(ehdr));
00173 if (0 > rv) {
00174 perror("read");
00175 goto out;
00176 }
00177 if (rv != sizeof(ehdr)) {
00178 fprintf(stderr, "elf error\n");
00179 goto out;
00180 }
00181 if (strncmp(ELFMAG, ehdr.e_ident, SELFMAG)) {
00182 fprintf(stderr, "not an elf\n");
00183 goto out;
00184 }
00185 if (sizeof(ELFXX_TYPE_Shdr) != ehdr.e_shentsize) {
00186 fprintf(stderr, "elf error\n");
00187 goto out;
00188 }
00189
00190
00191 size = ehdr.e_shentsize * ehdr.e_shnum;
00192 shdr = (ELFXX_TYPE_Shdr *) malloc(size);
00193 if (!shdr) {
00194 fprintf(stderr, "Out of memory\n");
00195 goto out;
00196 }
00197 rv = pread(fd, shdr, size, ehdr.e_shoff);
00198 if (0 > rv) {
00199 perror("read");
00200 goto out;
00201 }
00202 if (rv != size) {
00203 fprintf(stderr, "elf error");
00204 goto out;
00205 }
00206
00207
00208 size = shdr[ehdr.e_shstrndx].sh_size;
00209 shstrtab = (char *) malloc(size);
00210 if (!shstrtab) {
00211 fprintf(stderr, "Out of memory\n");
00212 goto out;
00213 }
00214 rv = pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset);
00215 if (0 > rv) {
00216 perror("read");
00217 goto out;
00218 }
00219 if (rv != size) {
00220 fprintf(stderr, "elf error\n");
00221 goto out;
00222 }
00223
00224
00225 symh = dynsymh = NULL;
00226 strh = dynstrh = NULL;
00227 for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++)
00228 if (SHT_SYMTAB == p->sh_type) {
00229 if (symh) {
00230 fprintf(stderr, "too many symbol tables\n");
00231 goto out;
00232 }
00233 symh = p;
00234 } else if (SHT_DYNSYM == p->sh_type) {
00235 if (dynsymh) {
00236 fprintf(stderr, "too many symbol tables\n");
00237 goto out;
00238 }
00239 dynsymh = p;
00240 } else if (SHT_STRTAB == p->sh_type
00241 && !strncmp(shstrtab+p->sh_name, ".strtab", 7)) {
00242 if (strh) {
00243 fprintf(stderr, "too many string tables\n");
00244 goto out;
00245 }
00246 strh = p;
00247 } else if (SHT_STRTAB == p->sh_type
00248 && !strncmp(shstrtab+p->sh_name, ".dynstr", 7)) {
00249 if (dynstrh) {
00250 fprintf(stderr, "too many string tables\n");
00251 goto out;
00252 }
00253 dynstrh = p;
00254 }
00255
00256 if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) {
00257 fprintf(stderr, "bad dynamic symbol table");
00258 goto out;
00259 }
00260 if ((!symh && strh) || (symh && !strh)) {
00261 fprintf(stderr, "bad symbol table");
00262 goto out;
00263 }
00264 if (!dynsymh && !symh) {
00265 fprintf(stderr, "no symbol table");
00266 goto out;
00267 }
00268
00269
00270 if (dynsymh)
00271 symtab->dyn = get_syms(fd, dynsymh, dynstrh);
00272 if (symh)
00273 symtab->st = get_syms(fd, symh, strh);
00274 ret = 0;
00275 out:
00276 free(shstrtab);
00277 free(shdr);
00278 return ret;
00279 }
00280
00281 static symtab_t
00282 load_symtab(char *filename)
00283 {
00284 int fd;
00285 symtab_t symtab;
00286
00287 symtab = (symtab_t) malloc(sizeof(*symtab));
00288 if (!symtab) {
00289 fprintf(stderr, "Out of memory\n");
00290 return NULL;
00291 }
00292 bzero(symtab, sizeof(*symtab));
00293
00294 fd = open(filename, O_RDONLY);
00295 if (0 > fd) {
00296 perror("open");
00297 return NULL;
00298 }
00299 if (0 > do_load(fd, symtab)) {
00300 fprintf(stderr, "Error ELF parsing %s\n", filename);
00301 free(symtab);
00302 symtab = NULL;
00303 }
00304 close(fd);
00305 return symtab;
00306 }
00307
00308 #define MYMAX(a,b) (a>b?a:b)
00309
00310 static int
00311 lookup2(struct symlist *sl, unsigned char type,
00312 char *name, unsigned long *val, unsigned int *size)
00313 {
00314 ELFXX_TYPE_Sym *p;
00315 int len;
00316 int i;
00317
00318 len = strlen(name);
00319 for (i = 0, p = sl->sym; i < sl->num; i++, p++) {
00320 int mlen = MYMAX(len, strlen(sl->str+p->st_name));
00321 if (!strncmp(sl->str+p->st_name, name, mlen)
00322 && ELFXX_ST_TYPE(p->st_info) == type) {
00323 *val = p->st_value;
00324 *size = p->st_size;
00325 return 0;
00326 }
00327 }
00328 return -1;
00329 }
00330
00331 static int
00332 lookup_sym(symtab_t s, unsigned char type,
00333 char *name, unsigned long *val, int *size)
00334 {
00335 if (s->dyn && !lookup2(s->dyn, type, name, val, size))
00336 return 0;
00337 if (s->st && !lookup2(s->st, type, name, val, size))
00338 return 0;
00339 return -1;
00340 }
00341
00342 static int
00343 load_memmap()
00344 {
00345 char raw[10000];
00346 char name[MAX_NAME_LEN];
00347 char *p;
00348 unsigned long start, end;
00349 struct mm *m;
00350 int fd, rv;
00351 int i;
00352
00353 fd = open("/proc/self/maps", O_RDONLY);
00354 if (0 > fd) {
00355 fprintf(stderr, "Can't open /proc/self/maps for reading\n");
00356 return -1;
00357 }
00358
00359
00360 bzero(raw, sizeof(raw));
00361 rv = read(fd, raw, sizeof(raw));
00362 if (0 > rv) {
00363 perror("read");
00364 return -1;
00365 }
00366 if (rv >= sizeof(raw)) {
00367 fprintf(stderr, "Too many memory mapping\n");
00368 return -1;
00369 }
00370 close(fd);
00371
00372 p = strtok(raw, "\n");
00373 m = mm;
00374 while (p) {
00375
00376 rv = sscanf(p, "%08lx-%08lx %*s %*s %*s %*s %s\n",
00377 &start, &end, name);
00378 p = strtok(NULL, "\n");
00379
00380 if (rv == 2) {
00381 m = &mm[nmm++];
00382 m->start = start;
00383 m->end = end;
00384 strcpy(m->name, MEMORY_ONLY);
00385 continue;
00386 }
00387
00388
00389 for (i = nmm-1; i >= 0; i--) {
00390 m = &mm[i];
00391 if (!strcmp(m->name, name))
00392 break;
00393 }
00394
00395 if (i >= 0) {
00396 if (start < m->start)
00397 m->start = start;
00398 if (end > m->end)
00399 m->end = end;
00400 } else {
00401
00402 m = &mm[nmm++];
00403 m->start = start;
00404 m->end = end;
00405 strcpy(m->name, name);
00406 }
00407 }
00408 return 0;
00409 }
00410
00411
00412
00413 static int
00414 match_libc(const char *name)
00415 {
00416 char *p;
00417
00418 p = strrchr(name, '/');
00419 if (!p)
00420 return 0;
00421 p++;
00422 if (strncmp("libc", p, 4))
00423 return 0;
00424 p += 4;
00425
00426
00427 if (!strncmp(".so", p, 3) || (p[0] == '-' && isdigit(p[1])))
00428 return 1;
00429 return 0;
00430 }
00431
00432
00433
00434
00435
00436 static int
00437 find_my_libc(char *name, int len, unsigned long *start)
00438 {
00439 int i;
00440 struct mm *m;
00441
00442 if (!nmm && 0 > load_memmap()) {
00443 fprintf(stderr, "cannot read my memory map\n");
00444 return -1;
00445 }
00446
00447 for (i = 0, m = mm; i < nmm; i++, m++) {
00448 if (!strcmp(m->name, MEMORY_ONLY))
00449 continue;
00450 if (match_libc(m->name))
00451 break;
00452 }
00453 if (i >= nmm)
00454
00455 return -1;
00456
00457 *start = m->start;
00458 strncpy(name, m->name, len);
00459 if (strlen(m->name) >= len)
00460 name[len-1] = '\0';
00461 return 0;
00462 }
00463
00464 static int
00465 patch(unsigned long from, unsigned long to)
00466 {
00467 unsigned char *p;
00468 int *q;
00469 size_t pgsize;
00470
00471
00472 pgsize = getpagesize();
00473 if (0 > mprotect((void *) (from & ~(pgsize - 1)), pgsize,
00474 PROT_READ|PROT_WRITE|PROT_EXEC))
00475 return -1;
00476
00477
00478 p = (unsigned char *) from;
00479 *p++ = 0xe9;
00480
00481
00482 q = (int *) p;
00483 *q = to - (from + 5);
00484
00485
00486 return 0;
00487 }
00488
00489
00490
00491 static symtab_t symtab;
00492 static unsigned long libc;
00493
00494 int
00495 lookup_obj_sym(char *name, unsigned long *val, int *size)
00496 {
00497 if(-1==lookup_sym(symtab, STT_OBJECT, name, val, size)
00498 &&-1==lookup_sym(symtab, STT_NOTYPE, name, val, size))
00499 return -1;
00500 else
00501 return 0;
00502 }
00503
00504 int
00505 init_symtab(char *exename)
00506 {
00507 char libcname[128];
00508
00509
00510
00511
00512
00513 symtab = load_symtab(exename);
00514
00515 if (!symtab)
00516 return -1;
00517 return 0;
00518 }
00519
00520
00521 #endif