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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ident "$Revision: 1.1.1.1 $"
00039
00040 #include <sys/types.h>
00041 #include <sys/syssgi.h>
00042 #include <sys/stat.h>
00043 #include <sys/mman.h>
00044 #include <fcntl.h>
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <unistd.h>
00048 #include <limits.h>
00049 #include <stdio.h>
00050 #include <elf_abi.h>
00051 #include <elf_mips.h>
00052 #include <string.h>
00053 #include <errno.h>
00054 #include <cmplrs/elfmap.h>
00055
00056 #define MAX_PAGE_SIZE 0x00010000
00057 #define OLDVM
00058 #define TWOMEG 0x200000
00059 #define TWOMEGMASK 0xffe00000
00060
00061 #define DPRINTF if (debug) printf
00062 #ifdef DEBUG
00063 static int debug = 1;
00064 #else
00065 static int debug = 0;
00066 #endif
00067
00068
00069 #define INITIAL_STATE 0
00070
00071
00072
00073 #define FILE_OPEN 2
00074 #define EH_ALLOC 3
00075 #define EH_SUCCESS 4
00076 #define PH_ALLOC 5
00077 #define PH_SUCCESS 6
00078 #define ISMAP_ALLOC 7
00079 #define SEG_MAPPED 8
00080 #define MAP_SUCCESS 9
00081
00082
00083 #define TRUE 1
00084 #define FALSE 0
00085
00086
00087 #define MAX_LOAD_SEGS 20
00088
00089
00090
00091 typedef struct {
00092 int state;
00093 int infd;
00094 void *retval;
00095 int *isMapped;
00096 int options;
00097 int isPIC;
00098 } em_environ;
00099
00100 typedef struct {
00101 void *mm_addr;
00102 int mm_len;
00103 int mm_prot;
00104 int mm_flags;
00105 off_t mm_off;
00106 int mm_filesz;
00107 } mm_vector;
00108
00109
00110
00111 static Elf32_Ehdr *getEhdr(em_environ *);
00112 static int validEhdr(Elf32_Ehdr *);
00113 static Elf32_Phdr *getPhdr(Elf32_Ehdr *, em_environ *);
00114 static void cleanup(em_environ *, Elf32_Ehdr *, Elf32_Phdr *);
00115 extern void error(char * fmt, ... );
00116
00117
00118 #if 0
00119 static void mapSegs(Elf32_Ehdr *, Elf32_Phdr *, em_environ *);
00120 static int domap(mm_vector *, int, unsigned, unsigned, em_environ *);
00121 static int trymap(mm_vector *, int, int, em_environ *);
00122 static int addrInUse(void *);
00123 #endif
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 Elf32_Addr
00138 _elfunmap(Elf32_Addr addr, int len) {
00139 return(elfunmap(addr,len));
00140 }
00141
00142 Elf32_Addr
00143 elfunmap(Elf32_Addr addr, int len) {
00144 Elf32_Addr map_addr = addr&~(getpagesize()-1);
00145 Elf32_Word diff = addr - map_addr;
00146
00147
00148 if (munmap((void *)map_addr,len+diff) < 0) {
00149 perror("elfunmap:");
00150 addr = (Elf32_Addr) -1;
00151 }
00152 return( addr );
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 Elf32_Addr
00172 _elfmap(char *path, int infd, int opts) {
00173
00174 return(elfmap(path,infd,opts));
00175 }
00176
00177 Elf32_Addr
00178 elfmap(char *path, int infd, int opts) {
00179
00180 int numloadseg = 0, i;
00181 Elf32_Ehdr *pEhdr;
00182 Elf32_Phdr *pPhdr;
00183 Elf32_Phdr *pPload=0, *ptr_first_text_page=0, *pPtemp;
00184 em_environ e;
00185 void *baseaddr;
00186 long map_diff;
00187
00188
00189 if (!infd && !path) {
00190 error("No file specified.");
00191 return( _EM_ERROR );
00192 }
00193
00194 if (!infd) {
00195
00196 DPRINTF("elfmap: opening file %s, opt = 0x%x\n", path, opts);
00197 e.state = INITIAL_STATE;
00198
00199 if ((infd = open(path, O_RDONLY)) == -1) {
00200 if (!(_EM_SILENT&opts)) perror("elfmap");
00201 cleanup(&e, 0, 0);
00202 return(_EM_ERROR);
00203 }
00204 }
00205
00206 e.state = FILE_OPEN;
00207 e.infd = infd;
00208 e.options = opts;
00209
00210
00211 DPRINTF("elfmap: reading ELF header.\n");
00212 pEhdr = getEhdr(&e);
00213 if (e.state != EH_SUCCESS) {
00214 cleanup(&e, pEhdr, 0);
00215 return(_EM_ERROR);
00216 }
00217
00218
00219 DPRINTF("elfmap: reading program header\n");
00220 pPhdr = getPhdr(pEhdr, &e);
00221 if (e.state != PH_SUCCESS) {
00222 error("Couldn't read Program header in %s.", path);
00223 cleanup(&e, pEhdr, pPhdr);
00224 return( _EM_ERROR );
00225 }
00226
00227 #ifndef OLD_SYSCALL
00228 if ((pPload = (Elf32_Phdr *)malloc(pEhdr->e_phnum * sizeof(Elf32_Phdr))) == NULL)
00229 error ("elfmap: cannot malloc for pPload");
00230
00231 for (i = 0; i<pEhdr->e_phnum; i++) {
00232 if (pPhdr[i].p_type == PT_LOAD) {
00233 memcpy(&pPload[numloadseg], &pPhdr[i], sizeof(Elf32_Phdr));
00234 numloadseg++;
00235 }
00236 }
00237
00238 if (numloadseg == 0) {
00239 error("elfmap: no PT_LOAD segment found in %s.", path);
00240 cleanup(&e, pEhdr, pPhdr);
00241 return(_EM_ERROR);
00242 }
00243
00244 baseaddr = (void *) syssgi(SGI_ELFMAP, e.infd, pPload, numloadseg);
00245 if ((long)baseaddr < 0) {
00246 error("elfmap: couldn't map file %s -- error code %d.", path, errno);
00247 cleanup(&e, pEhdr, pPhdr);
00248 return(_EM_ERROR);
00249 }
00250
00251
00252
00253
00254
00255
00256 map_diff = (long) baseaddr - (long)pPload->p_vaddr;
00257
00258 pPtemp = pPload;
00259 for (i = 0; i < numloadseg; i++) {
00260 if ((ptr_first_text_page == 0) || (pPtemp->p_offset < ptr_first_text_page->p_offset)) {
00261 if (pPtemp->p_flags & (PF_X))
00262 ptr_first_text_page = pPtemp;
00263 }
00264 pPtemp++;
00265 }
00266
00267 baseaddr = (void *)((ptr_first_text_page->p_vaddr) +
00268 map_diff - ptr_first_text_page->p_offset);
00269 free(pPload);
00270 #else
00271
00272 DPRINTF("elfmap: allocating isMapped array\n");
00273 e.isMapped = (int *) calloc(pEhdr->e_phnum, sizeof(int));
00274 if (e.isMapped == NULL) {
00275 cleanup(&e, pEhdr, pPhdr);
00276 return( _EM_ERROR );
00277 }
00278 e.state = ISMAP_ALLOC;
00279
00280
00281 DPRINTF("elfmap: mapping segments\n");
00282 mapSegs(pEhdr, pPhdr, &e);
00283 if (e.state != MAP_SUCCESS) {
00284 baseaddr = (void *) _EM_ERROR;
00285 } else {
00286 baseaddr = e.retval;
00287 }
00288 #endif
00289 cleanup(&e, pEhdr, pPhdr);
00290 return((Elf32_Addr) baseaddr);
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 #ifdef RLD_ELFMAP
00307 extern char *hbuffer;
00308 extern size_t hbuffersize, hbsize;
00309 #else
00310 #define HBUFSIZE 512
00311 static char hbuffer[HBUFSIZE];
00312 static size_t hbuffersize = HBUFSIZE, hbsize = HBUFSIZE;
00313 #endif
00314 static int ehdr_malloced;
00315 static int phdr_malloced;
00316
00317 static Elf32_Ehdr
00318 *getEhdr(em_environ *e)
00319 {
00320 Elf32_Ehdr *pEhdr = 0;
00321 size_t rsize = hbuffersize;
00322
00323 if (read(e->infd, (void *) hbuffer, rsize) == rsize ) {
00324
00325 pEhdr = (Elf32_Ehdr *) hbuffer;
00326 ehdr_malloced = 0;
00327
00328 } else {
00329
00330 rsize = sizeof(Elf32_Ehdr);
00331
00332
00333 if (rsize > hbuffersize) {
00334 pEhdr = (Elf32_Ehdr *) malloc(rsize);
00335 hbsize = 0;
00336 ehdr_malloced = 1;
00337 } else {
00338 pEhdr = (Elf32_Ehdr *) hbuffer;
00339 hbsize = rsize;
00340 ehdr_malloced = 0;
00341 }
00342
00343 if (pEhdr == NULL) {
00344 error("elfmap: out of memory.");
00345 DPRINTF("Couldn't allocate pEhdr");
00346 return(NULL);
00347 }
00348 e->state=EH_ALLOC;
00349
00350
00351 if(read(e->infd, (void *) pEhdr, rsize) != rsize) {
00352 error("elfmap: Unexpected EOF");
00353 return(pEhdr);
00354 }
00355 }
00356
00357
00358 if (rsize < pEhdr->e_ehsize) {
00359 rsize = pEhdr->e_ehsize;
00360 DPRINTF("***Size mismatch - Reallocating\n");
00361 pEhdr = (Elf32_Ehdr *) realloc(pEhdr,rsize);
00362 if(read(e->infd, (void *) pEhdr, rsize) != rsize) {
00363 error("elfmap: Unexpected EOF");
00364 cleanup(e, pEhdr, NULL);
00365 return(pEhdr);
00366 }
00367 }
00368
00369
00370
00371 if (validEhdr(pEhdr)) {
00372 e->state = EH_SUCCESS;
00373 }
00374
00375
00376 e->isPIC = (int)pEhdr->e_flags & EF_MIPS_PIC;
00377
00378 return(pEhdr);
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 static int
00394 validEhdr(Elf32_Ehdr *pEhdr)
00395 {
00396 unsigned char *ident;
00397
00398
00399 ident = pEhdr->e_ident;
00400 if ( (ident[EI_MAG0] != 0x7f) || (ident[EI_MAG1] != 'E')
00401 || (ident[EI_MAG2] != 'L') || (ident[EI_MAG3] != 'F') ) {
00402 error("elfmap: not an ELF file.");
00403 return(FALSE);
00404 }
00405
00406
00407
00408
00409
00410
00411 if (ident[EI_DATA] != ELFDATA2MSB) {
00412 error("elfmap: object is opposite Endian from me.");
00413 return(FALSE);
00414 }
00415
00416
00417 if (ident[EI_CLASS] != ELFCLASS32) {
00418 error("elfmap: object has invalid class,");
00419 return(FALSE);
00420 }
00421
00422 if ((pEhdr->e_machine != EM_NONE) && (pEhdr->e_machine != EM_MIPS)) {
00423 error("elfmap: object is not for this machine.");
00424 return(FALSE);
00425 }
00426
00427
00428 if ((pEhdr->e_type != ET_EXEC) && (pEhdr->e_type != ET_DYN)) {
00429 error("elfmap: object is not an executable or dynamic object.");
00430 return(FALSE);
00431 }
00432
00433 if ((pEhdr->e_flags & EF_MIPS_ABI2) == EF_MIPS_ABI2) {
00434 error("elfmap: object should NOT be a ABI2 -- new ABI 32bit object.");
00435 return(FALSE);
00436 }
00437
00438 return(TRUE);
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 static Elf32_Phdr
00454 *getPhdr(Elf32_Ehdr *pE, em_environ *e)
00455 {
00456 Elf32_Phdr *pPhdr;
00457 unsigned size;
00458
00459
00460 size = pE->e_phentsize * pE->e_phnum;
00461 if (hbsize >= pE->e_phoff + size) {
00462
00463 pPhdr = (Elf32_Phdr *)(hbuffer + pE->e_phoff);
00464 phdr_malloced = 0;
00465 } else {
00466
00467 pPhdr = (Elf32_Phdr *) calloc((size_t) pE->e_phentsize, pE->e_phnum);
00468 phdr_malloced = 1;
00469 if (pPhdr == NULL) {
00470 error("elfmap: cant allocate space for program header.");
00471 return(NULL);
00472 }
00473 e->state = PH_ALLOC;
00474
00475
00476 if (lseek(e->infd, (off_t)pE->e_phoff, SEEK_SET)
00477 != (off_t)pE->e_phoff) {
00478 error("elfmap: lseek failed.");
00479 return(NULL);
00480 }
00481
00482 if (read(e->infd, (void *)pPhdr, size) != size) {
00483 error("elfmap: read of program header failed.");
00484 return(NULL);
00485 }
00486
00487 }
00488 e->state = PH_SUCCESS;
00489 return (pPhdr);
00490 }
00491
00492 #ifdef OLD_SYSCALL
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 static void
00512 mapSegs(Elf32_Ehdr *pEhdr, Elf32_Phdr *pPhdr, em_environ *e) {
00513
00514 int phIndex;
00515 unsigned pgsz;
00516 unsigned pgmsk;
00517 mm_vector mmargs[MAX_LOAD_SEGS];
00518 int cur_load_seg=0;
00519 void *vaddr;
00520 off_t offset;
00521 int len;
00522 int flags;
00523 int prot;
00524 unsigned minaddr = 0x7fffffff;
00525 unsigned maxaddr = 0;
00526
00527 pgsz = getpagesize();
00528 pgmsk = pgsz - 1;
00529
00530
00531 for (phIndex=0; phIndex < pEhdr->e_phnum; phIndex++) {
00532
00533
00534 if (pPhdr[phIndex].p_type != PT_LOAD) continue;
00535
00536
00537
00538
00539
00540 offset = (off_t) pPhdr[phIndex].p_offset;
00541 vaddr = (void *) pPhdr[phIndex].p_vaddr;
00542 if((len = pPhdr[phIndex].p_memsz) < pPhdr[phIndex].p_filesz) {
00543 error("elfmap: loadable segment memsz is smaller than filesz.");
00544 return;
00545 }
00546
00547
00548 if ((unsigned)vaddr < minaddr) {
00549 minaddr = (unsigned) vaddr;
00550 }
00551 if ((unsigned)vaddr+pPhdr[phIndex].p_memsz > maxaddr) {
00552 maxaddr = (unsigned) vaddr+pPhdr[phIndex].p_memsz;
00553 }
00554
00555 prot = 0;
00556 prot |= ((pPhdr[phIndex].p_flags & PF_R) ? PROT_READ : 0);
00557 prot |= ((pPhdr[phIndex].p_flags & PF_W) ? PROT_WRITE : 0);
00558 prot |= ((pPhdr[phIndex].p_flags & PF_X) ? PROT_EXECUTE : 0);
00559
00560
00561
00562
00563 if ((e->options & _EM_DEBUG_TEXT) && (prot & PROT_EXECUTE)) {
00564 prot |= PROT_WRITE;
00565 }
00566
00567
00568 flags = MAP_FIXED;
00569
00570
00571
00572
00573
00574
00575
00576 #ifdef _DELTA_C_PLUS_PLUS
00577 flags |= MAP_PRIVATE;
00578 #else
00579 flags |= ((prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED);
00580 #endif
00581 #ifdef OLDVM
00582 if (len > pPhdr[phIndex].p_filesz) {
00583 flags |= MAP_AUTOGROW;
00584 len = (len + TWOMEG) & TWOMEGMASK;
00585 }
00586 #else
00587
00588
00589
00590
00591
00592
00593 #endif
00594
00595 mmargs[cur_load_seg].mm_addr = vaddr;
00596 mmargs[cur_load_seg].mm_len = len;
00597 mmargs[cur_load_seg].mm_prot = prot;
00598 mmargs[cur_load_seg].mm_flags = flags;
00599 mmargs[cur_load_seg].mm_off = offset;
00600 mmargs[cur_load_seg].mm_filesz = pPhdr[phIndex].p_filesz;
00601
00602 if (cur_load_seg++ == MAX_LOAD_SEGS) {
00603 fatal("elfmap: too many loadable segs");
00604 }
00605
00606 }
00607
00608 if(domap(mmargs, cur_load_seg, minaddr, maxaddr, e)) {
00609 e->state = MAP_SUCCESS;
00610 }
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 static int
00631 domap(mm_vector *args,
00632 int count,
00633 unsigned min,
00634 unsigned max,
00635 em_environ *e) {
00636
00637 void *newaddr;
00638 int newoffset;
00639
00640
00641 if(trymap(args, count, 0, e)) {
00642 e->state = MAP_SUCCESS;
00643 return(TRUE);
00644 }
00645
00646
00647 if (!e->isPIC) {
00648
00649
00650
00651 error("elfmap: Non-PIC file cant be mapped.");
00652 return(FALSE);
00653 }
00654
00655
00656
00657
00658 {
00659 int zfd;
00660 int zflags = MAP_PRIVATE;
00661 int zprot = PROT_READ;
00662
00663 zfd = open("/dev/zero", O_RDONLY);
00664 newaddr = mmap((void *)0, max-min, zprot, zflags, zfd, 0);
00665 close(zfd);
00666 if ((int)newaddr == -1) {
00667 error("elfmap: can't map space for object.");
00668 return(FALSE);
00669 }
00670 munmap(newaddr,max-min);
00671 }
00672
00673
00674
00675
00676
00677 newoffset = (int)newaddr-min;
00678 if (trymap(args, count, newoffset, e)) {
00679 e->state = MAP_SUCCESS;
00680 return(TRUE);
00681 }
00682
00683 return(FALSE);
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 static int
00697 trymap(mm_vector *args, int numargs, int offset, em_environ *e) {
00698 int i;
00699
00700 for (i=0; i< numargs; i++) {
00701 void *curaddr;
00702
00703 curaddr = (void *)((int)args[i].mm_addr + offset);
00704
00705
00706 if(addrInUse(curaddr)) break;
00707
00708 if (mmap(curaddr, args[i].mm_len, args[i].mm_prot,
00709 args[i].mm_flags, e->infd, args[i].mm_off) != curaddr) {
00710 break;
00711 }
00712
00713
00714 if ( args[i].mm_len > args[i].mm_filesz ) {
00715 void *bss_start = (void *)((int) curaddr + args[i].mm_filesz);
00716 int bss_len = args[i].mm_len - args[i].mm_filesz;
00717 bzero(bss_start, bss_len);
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728 if (args[i].mm_off == 0) e->retval = curaddr;
00729 }
00730
00731 if (i == numargs) {
00732
00733 return(TRUE);
00734 }
00735
00736
00737 while (i > 0) {
00738 void *curaddr;
00739 i--;
00740 curaddr = (void *)((int)args[i].mm_addr + offset);
00741 munmap(curaddr, args[i].mm_len);
00742 }
00743
00744 return(FALSE);
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 static int
00758 addrInUse(void *addr) {
00759 unsigned len;
00760
00761 len = getpagesize();
00762
00763 if (mpin(addr, len) == -1) {
00764 return(FALSE);
00765 } else {
00766 munpin(addr, len);
00767 return(TRUE);
00768 }
00769 }
00770 #endif
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 static void
00782 cleanup(em_environ *e, Elf32_Ehdr *pE, Elf32_Phdr *pP)
00783 {
00784
00785 int i;
00786
00787 switch(e->state) {
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 case SEG_MAPPED:
00801
00802
00803
00804
00805
00806 for (i = 0; i < pE->e_phnum; i++) {
00807 if (e->isMapped[i]) {
00808 elfunmap((Elf32_Addr) pP[i].p_vaddr, (int) pP[i].p_memsz);
00809 }
00810 }
00811
00812 case MAP_SUCCESS:
00813 case ISMAP_ALLOC:
00814 free(e->isMapped);
00815
00816 case PH_SUCCESS:
00817 case PH_ALLOC:
00818 if (phdr_malloced) free(pP);
00819
00820 case EH_SUCCESS:
00821 case EH_ALLOC:
00822 if (ehdr_malloced) free(pE);
00823
00824 case FILE_OPEN:
00825 close(e->infd);
00826
00827 case INITIAL_STATE:
00828
00829 break;
00830
00831 default:
00832 printf("Bogus state in elfmap:cleanup: %d\n",e->state);
00833 exit(10);
00834 }
00835 }
00836
00837