Sets the brk pointer for save-the-world binaries to what it was when each
[dyninst.git] / dyninstAPI_RT / src / RTmutatedBinary_ELF.c
1 /*
2  * Copyright (c) 1996-2004 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /* $Id: RTmutatedBinary_ELF.c,v 1.21 2006/01/13 00:00:48 jodom Exp $ */
43
44 /* this file contains the code to restore the necessary
45    data for a mutated binary 
46  */
47
48 #include <stdlib.h>
49 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
50 #include <unistd.h>
51 #include  <fcntl.h>
52 #include <string.h>
53
54 #include <libelf.h>
55
56
57
58 #if defined(sparc_sun_solaris2_4)
59 #include <procfs.h> /* ccw 12 mar 2004*/
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #endif
63
64
65
66 #if defined(i386_unknown_linux2_0) \
67  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
68 #define __USE_GNU
69 #endif
70
71 #include <sys/mman.h>
72 #include <dlfcn.h>
73 #include <link.h> /* ccw 23 jan 2002 */
74 #if defined(sparc_sun_solaris2_4) 
75
76 #include <sys/link.h>
77 #include <signal.h>
78 #endif
79 #include <limits.h>
80
81 #if defined(sparc_sun_solaris2_4)
82 extern void* _DYNAMIC;
83
84 #if defined(__arch64__)
85 #define __ELF_NATIVE_CLASS 64
86 #else
87 #define __ELF_NATIVE_CLASS 32
88 #endif
89
90 /* Borrowed from Linux's link.h:  Allows us to use data types
91    from libelf regardless of word size. */
92 #define ElfW(type)      _ElfW (Elf, __ELF_NATIVE_CLASS, type)
93 #define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
94 #define _ElfW_1(e,w,t)  e##w##t
95
96
97 #elif defined(i386_unknown_linux2_0) \
98    || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
99 extern ElfW(Dyn) _DYNAMIC[];
100
101 #endif
102
103 /* Borrowed from Linux's link.h: Allows us to use functions from
104    libelf regardless of word size. */
105 //#define ELF_FUNC(type)      _ELF_FUNC (elf, __ELF_NATIVE_CLASS, type)
106 #define ELF_FUNC(type)      _ELF_FUNC (Elf, __ELF_NATIVE_CLASS, type)
107 #define _ELF_FUNC(e,w,t)    _ELF_FUNC_1 (e, w, _##t)
108 #define _ELF_FUNC_1(e,w,t)  e##w##t
109
110 typedef struct {
111       ElfW(Sword) d_tag;
112       union {
113           ElfW(Sword) d_val;
114           ElfW(Addr) d_ptr;
115       } d_un;
116   } __Elf_Dyn;
117
118 unsigned long checkAddr;
119 /*extern int isMutatedExec;
120 char *buffer;
121 */
122
123 struct link_map* map=NULL;
124
125 #if defined(sparc_sun_solaris2_4)
126
127 prmap_t *procMemMap=NULL;/* ccw 2 apr 2002 */
128 int procMemMapSize=0;
129
130 struct r_debug _r_debug; /* ccw 2 apr 2002 */
131 int r_debug_is_set = 0; 
132 extern unsigned int _dyninst_call_to_dlopen;
133 extern unsigned int __dyninst_jump_template__;
134 extern unsigned int __dyninst_jump_template__done__;
135 #endif
136
137 char *sharedLibraryInfo = NULL;
138 unsigned int originalInsnBkpt;
139 unsigned int addressBkpt;
140
141 #if defined(sparc_sun_solaris2_4)
142 /*      To help the RT shared lib to reload in the same location for the
143         mutated binaries we now use dldump to dump the rt lib back to the
144         directory that contains the mutated binary.  The LD_LIBRARY_PATH
145         MUST be set to find this new rt lib ONLY when running the mutated
146         binary.
147 */
148 extern char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
149
150 int DYNINSTsaveRtSharedLibrary(char *rtSharedLibName, char *newName){
151
152         char *err_str;
153         gLoadLibraryErrorString[0]='\0';
154
155         /*fprintf(stderr," DLDUMP(%s,%s)\n",  rtSharedLibName, newName);*/
156
157         /* dldump returns 0 on success */
158         if ( dldump(rtSharedLibName, newName, RTLD_REL_RELATIVE) ) { 
159                 /* An error has occurred */
160                 perror( "DYNINSTsaveRtSharedLibrary -- dldump" );
161     
162                 if (NULL != (err_str = dlerror())){
163                         strncpy(gLoadLibraryErrorString, err_str, ERROR_STRING_LENGTH);
164                 }else{ 
165                         sprintf(gLoadLibraryErrorString,"unknown error with dldump");
166                 }
167     
168                 /*fprintf(stderr, "%s[%d]: %s\n",__FILE__,__LINE__,gLoadLibraryErrorString);*/
169                 return 0;  
170         } else{
171                 return 1;
172         }
173 }
174 #endif
175 /*      this is not misnamed.  In the future, this function will contain
176         code to patch the instrumentation of a shared library that has 
177         been loaded into a different place during a mutated binary run.
178
179         Now, it just exit()s, as you can see
180 */
181
182 void fixInstrumentation(char* soName, unsigned long currAddr, unsigned long oldAddr){
183         printf(" %s loaded at wrong address: 0x%lx (expected at 0x%lx) \n", soName, currAddr, oldAddr);
184         printf(" This is an unrecoverable error, the instrumentation will not");
185         printf("\n run correctly if shared libraries are loaded at a different address\n");
186         printf("\n Exiting.....\n");
187         fflush(stdout);
188         exit(9);
189 }
190
191 /*      this function checks the shared library (soName) to see if it
192         is currently loaded (loadAddr) at the same place it was before (address).
193         If the shared library is not found in the list (sharedLibraryInfo) that
194         mean the shared library was *NOT* instrumented and can be loaded
195         anywhere
196 */
197 unsigned long checkSOLoadAddr(char *soName, unsigned long loadAddr){
198         unsigned long result=0, found = 0;
199         unsigned long address;
200         char *ptr = sharedLibraryInfo;
201         while(ptr &&  *ptr && !found ){
202                 /*fprintf(stderr," CHECKING FOR %s in %s\n", ptr, soName);*/
203
204                 if(strstr(soName, ptr) || strstr(ptr,soName)){
205                         found = 1;
206                         ptr += (strlen(ptr) +1);
207                         memcpy(&address, ptr, sizeof(unsigned long)); 
208                         /* previous line is done b/c of alignment issues on sparc*/
209                         if(loadAddr == address) {
210                                 result = 0;
211                         }else{
212                                 result = address;
213                         }       
214                 }
215
216                 ptr += (strlen(ptr) +1);
217                 ptr += sizeof(unsigned long);
218                 ptr += sizeof(unsigned long); /* for flag */
219
220
221         }
222         if(!found){
223                 result = 0;
224                 /*fprintf(stderr," NOT FOUND %s\n",soName);*/
225         }
226
227         /*fprintf(stderr," checkSOLoadAddr: %s %lx %lx\n", soName, loadAddr, result);*/
228         return result;
229 }
230 #if defined(sparc_sun_solaris2_4)
231 unsigned int register_o7;
232
233 unsigned long loadAddr;
234 /*      this function is not a signal handler. it was originally but now is 
235         not, it is called below in dyninst_jump_template
236 */ 
237 void pseudoSigHandler(int sig){
238
239         map = _r_debug.r_map; /* ccw 22 jul 2003*/
240         if(_r_debug.r_state == 0){
241                 do{
242                         if(map->l_next){
243                                 map = map->l_next;
244                         }
245                         loadAddr = checkSOLoadAddr(map->l_name, map->l_addr);
246                         if(loadAddr){
247                                 fixInstrumentation(map->l_name, map->l_addr, loadAddr);
248                         }
249
250                 }while(map->l_next);
251
252         }
253
254 }
255
256 void dyninst_jump_template(){
257 /* THE PLAN:
258
259         The Solaris loader/ELF file works as follows:
260         
261         A call to dlopen jumps to the Procedure Linking Table 
262         slot holding the dlopen information.  This slot consists of
263         three instructions:
264         
265         sethi r1, 0xb4
266         ba (to another PLT slot)
267         nop
268
269         The second PLT slot contains three instructions:
270         save
271         call (address of dlopen)
272         nop
273
274         dlopen returns directly to where it was called from, not to
275         either of the PLT slots.  The address from which it was called
276         is located in %o7 when the call to dlopen in the second PLT
277         slot is made. dlopen returns to %o7 +4.
278         
279
280         What our code does:
281
282         The goals is to intercept this call to dlopen by overwritting
283         the first PLT slot to jump to __dyninst_jump_template__ then we
284         can jump to code that will check the addresses of the loaded
285         shared libraries.
286
287         first we must preserver %o7 so we know where to go back to.
288         This is done with the first two instructions in __dyninst_jump_template__
289         These are written as nops BUT are overwritten in the SharedLibraries 
290         branch in checkElfFile.  %o7 is saved in register_o7 declared above.
291         This address is not available until run time so we generate these
292         instructions on the fly.
293
294         Next, we CALL the second PLT slot as normal.  We use the delay
295         slot to run the sethi instruction from the first PLT slot. These
296         instructions are generated at runtime. 
297
298         dlopen will eventually be called and will return to the nop after
299         the sethi.  Now we need to call our function to check the
300         shared library address.  This is pseudoSigHandler.  We must
301         preserve the data returned by dlopen so we do a save to
302         push the register onto the stack before we call our function.
303         We call our function, and then do a restore to retreive the 
304         saved information.
305
306         At __dyninst_jump_template__done__ we want to restore the
307         value in register_o7 to %o7 so when we do a retl we will
308         jump back to where the mutated binary originally called 
309         dlopen.
310         The sethi and ld instructions are generated on the fly just
311         as the first sethi and st pair that saved the value of %o7.
312         The retl used %o7 to jump back to the original place 
313         the mutatee called dlopen. We are done. Whew.
314
315         Note that I know the address of the first PLT slot because
316         the mutator found it and saved it in the mutated binary.
317         The address of the second PLT slot is determined by looking
318         at the instructions in the first PLT slot.
319 */
320         
321
322         asm("nop");
323         asm("__dyninst_jump_template__:");
324
325         asm("nop");     /*sethi hi(register_o7), %g1 GENERATED BELOW*/
326         asm("nop");     /*st %o7 GENERATED BELOW*/
327
328         asm("nop");     /*call/jmp plt GENERATED BELOW*/
329         asm("nop");    /*sethi r1, b4 GENERATED BELOW*/
330
331         asm("nop");
332         asm("save %sp, -104, %sp");
333         asm("nop");
334         pseudoSigHandler(0);
335         asm("nop");
336         asm("restore");
337         asm("nop");
338         asm("nop");
339         asm("__dyninst_jump_template__done__:");
340         asm("nop");     /*sethi hi(register_o7), %g1 GENERATED BELOW*/
341         asm("nop");     /* ld [register_o7], %o7 GENERATED BELOW*/
342         asm("retl");
343
344         asm("nop");     /* this will be filled in below */
345         asm("nop");
346
347 }
348
349 #endif
350
351 #if defined (sparc_sun_solaris2_4)
352 void findMap(){ /* ccw 12 mar 2004*/
353
354         Dl_info dlip;
355         int me = getpid();
356         char fileName[1024];
357         prmap_t mapEntry;
358         int fd;
359         int index = 0;
360         int offset = 0;
361         struct stat statInfo;
362
363         sprintf(fileName, "/proc/%d/map", me);
364         
365         stat(fileName, &statInfo);
366         if( procMemMap ) {
367                 free(procMemMap);
368         }
369         procMemMap = (prmap_t*) malloc(statInfo.st_size);
370
371         fd = open(fileName, O_RDONLY);
372
373         while( pread(fd, (void*)& (procMemMap[index]), sizeof(mapEntry), offset) ){
374                 offset += sizeof(prmap_t);
375                 index++;
376         }
377         close(fd);
378         procMemMapSize = index;
379
380 }
381
382 long checkMap(unsigned long addr){
383         int index=0;
384
385         findMap();      
386         while(index < procMemMapSize){
387                 if( procMemMap[index].pr_vaddr <= addr && (procMemMap[index].pr_vaddr + (unsigned int)procMemMap[index].pr_size) > addr){
388                         return 1;
389                 }
390                 index++;
391         }
392         return 0;
393 }
394 #endif
395
396 #if defined(i386_unknown_linux2_0) \
397  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
398 unsigned long loadAddr;
399 void (*dl_debug_state_func)(void);
400
401 void dyninst_dl_debug_state(){
402         asm("nop");
403         if(_r_debug.r_state == 1){
404         do {
405                         if(map->l_next){
406                                 map = map->l_next;
407                         }
408                         loadAddr = checkSOLoadAddr(map->l_name, (unsigned long)map->l_ld);/*l_addr*/
409                         if(loadAddr){
410                                 fixInstrumentation(map->l_name, (unsigned long)map->l_ld, loadAddr);/*l_addr*/
411                         }
412                 }while(map->l_next);
413
414         }
415
416         /* the following call is used to call
417          * _dl_debug_state to ensure correctness (if
418          * someone relies on it being called it is
419          * execuated after this function)
420          * The value stored in dl_debug_state_func is
421          * the address of the function _dl_debug_state
422          * and is set in checkElfFile
423          */
424         asm("nop");
425         asm("nop");
426         asm("nop");
427         (*dl_debug_state_func)();
428         asm("nop");
429
430 }
431
432 void hack_ld_linux_plt(unsigned long pltEntryAddr){ 
433 /* this is ugly.
434  * save the world needs to check each shared library
435  * that is loaded to ensure that it is loaded at the
436  * same base address it was loaded at when the mutator/mutatee
437  * pair ran.  
438  * So, we know dlopen calls _dl_debug_state per the r_debug
439  * interface to let the process know a shared library has changed
440  * state.
441  * with this function we change the Procedure Linkage Table (.plt)
442  * for ld-linux.so so that the entry that used to point to
443  * _dl_debug_state points to dyninst_dl_debug_state.
444  *
445  * dyninst_dl_debug_state then calls _dl_debug_state before
446  * exiting 
447  *
448  * dont try this at home
449  */
450         unsigned long mprotectAddr = pltEntryAddr - (pltEntryAddr % getpagesize());     
451         unsigned long newTarget = (unsigned long) &dyninst_dl_debug_state ;
452         
453         mprotect( (void*) mprotectAddr, pltEntryAddr - mprotectAddr + sizeof(long), 
454                                 PROT_READ|PROT_WRITE|PROT_EXEC);
455
456         memcpy( (void*) dl_debug_state_func, (void*) pltEntryAddr, sizeof(long)); 
457
458         memcpy( (void*) pltEntryAddr, &newTarget, sizeof(long));
459 }
460 #endif
461
462 unsigned (*Elf_version)(unsigned) = NULL;
463 Elf *(*Elf_begin)(int fildes, Elf_Cmd cmd, Elf *ref) = NULL;
464 Elf_Scn *(*Elf_getscn)(Elf *elf, size_t index) = NULL;
465 Elf_Data *(*Elf_getdata)(Elf_Scn *scn, Elf_Data *data) = NULL;
466 Elf_Scn *(*Elf_nextscn)(Elf *elf, Elf_Scn *scn) = NULL;
467 Elf32_Shdr *(*Elf32_getshdr)(Elf_Scn *scn) = NULL;
468 Elf32_Ehdr *(*Elf32_getehdr)(Elf *elf) = NULL;
469 Elf64_Shdr *(*Elf64_getshdr)(Elf_Scn *scn) = NULL;
470 Elf64_Ehdr *(*Elf64_getehdr)(Elf *elf) = NULL;
471 const char *(*Elf_errmsg)(int err) = NULL;
472 int (*Elf_errno)(void) = NULL;
473 int (*Elf_end)(Elf *elf) = NULL;
474
475
476 int checkSO(char* soName){
477         ElfW(Shdr) *shdr;
478         ElfW(Ehdr) *   ehdr;
479         Elf *          elf;
480         int       fd;
481         Elf_Data *strData;
482         Elf_Scn *scn;
483         int result = 0;
484
485         if((fd = (int) open(soName, O_RDONLY)) == -1){
486                 RTprintf("cannot open : %s\n",soName);
487                 fflush(stdout); 
488                 return result;
489         }
490         if((elf = Elf_begin(fd, ELF_C_READ, NULL)) ==NULL){
491                 RTprintf("%s %s \n",soName, Elf_errmsg(Elf_errno()));
492                 RTprintf("cannot elf_begin\n");
493                 fflush(stdout);
494                 close(fd);
495                 return result;
496         }
497
498         ehdr = ELF_FUNC( getehdr(elf) );
499         scn = Elf_getscn(elf, ehdr->e_shstrndx);
500         strData = Elf_getdata(scn,NULL);
501         for( scn = NULL; !result && (scn = Elf_nextscn(elf, scn)); ){
502                 shdr = ELF_FUNC( getshdr(scn) );
503                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, ".dyninst_mutated")) {
504                         result = 1;
505                 }
506         }
507         Elf_end(elf);
508         close(fd);
509
510         return result;
511 }
512
513 int checkMutatedFile(){
514
515
516         ElfW(Shdr) *shdr;
517         ElfW(Ehdr) *   ehdr;
518         Elf *          elf;
519         int       cnt,fd;
520         Elf_Data *elfData,*strData;
521         Elf_Scn *scn;
522         char *execStr;
523         int retVal = 0, result;
524         unsigned long mmapAddr;
525         int pageSize;
526         Address dataAddress;
527         int dataSize;
528         char* tmpPtr;
529         unsigned long updateAddress, updateSize, updateOffset;
530         unsigned long *dataPtr;
531         unsigned int numberUpdates,i ;
532         char* oldPageData;
533         Dl_info dlip;
534         int soError = 0; 
535
536      char * error_msg = NULL;
537      void * elfHandle = NULL;
538
539
540
541 //     elfHandle = dlopen("/usr/lib/libelf.so.1", RTLD_NOW);
542
543      elfHandle = dlopen("libelf.so", RTLD_NOW);
544      if(! elfHandle){
545         error_msg = dlerror();
546         if (error_msg) {
547           fprintf(stderr,"Could not open lib: %s- %s\n","libelf",error_msg);
548         }
549         else{
550           fprintf(stderr, "failure\n");
551         }
552         exit(1);
553      }
554
555      Elf_version = dlsym(elfHandle, "elf_version");
556      Elf_begin = dlsym(elfHandle, "elf_begin");
557      Elf_getscn = dlsym(elfHandle, "elf_getscn");
558      Elf_nextscn = dlsym(elfHandle, "elf_nextscn");
559      Elf_getdata = dlsym(elfHandle, "elf_getdata");
560      Elf32_getehdr = dlsym(elfHandle, "elf32_getehdr");
561      Elf32_getshdr = dlsym(elfHandle, "elf32_getshdr");
562      Elf64_getehdr = dlsym(elfHandle, "elf64_getehdr");
563      Elf64_getshdr = dlsym(elfHandle, "elf64_getshdr");
564      Elf_errmsg = dlsym(elfHandle, "elf_errmsg");
565      Elf_errno = dlsym(elfHandle, "elf_errno");
566      Elf_end = dlsym(elfHandle, "elf_end");
567
568         Elf_version(EV_CURRENT);
569
570         execStr = (char*) malloc(1024);
571         memset(execStr,'\0',1024);
572
573 #if defined(sparc_sun_solaris2_4)
574         sprintf(execStr,"/proc/%d/object/a.out",getpid());
575 #elif defined(i386_unknown_linux2_0) \
576    || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
577         sprintf(execStr,"/proc/%d/exe",getpid());
578 #endif
579
580         if((fd = (int) open(execStr, O_RDONLY)) == -1){
581                 printf("cannot open : %s\n",execStr);
582                 fflush(stdout); 
583                 return retVal;
584         }
585         if((elf = Elf_begin(fd, ELF_C_READ, NULL)) ==NULL){
586                 printf("%s %s \n",execStr, Elf_errmsg( Elf_errno()));
587                 printf("cannot Elf_begin\n");
588                 fflush(stdout);
589                 close(fd);
590                 return retVal;
591         }
592
593         ehdr = ELF_FUNC( getehdr(elf) );
594         scn = Elf_getscn(elf, ehdr->e_shstrndx);
595         strData = Elf_getdata(scn,NULL);
596         pageSize =  getpagesize();
597
598         /*fprintf(stderr,"IN MUTATED FILE\n");*/
599         for(cnt = 0, scn = NULL; !soError &&  (scn = Elf_nextscn(elf, scn));cnt++){
600                 shdr = ELF_FUNC( getshdr(scn) );
601                 if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPItrampgu", 17)) {
602                         dataAddress = shdr->sh_addr;
603                         elfData = Elf_getdata(scn, NULL);
604                         tmpPtr = elfData->d_buf;
605                         /*fprintf(stderr,"tramp guard addr %x %d\n", dataAddress,*(int*)tmpPtr);*/
606
607
608 #if defined(sparc_sun_solaris2_4)
609                         findMap();
610                         checkAddr = checkMap((unsigned long)shdr->sh_addr);
611 #else
612                         checkAddr = dladdr((void*)shdr->sh_addr, &dlip);
613 #endif
614                         if( !checkAddr ){
615                                 /* we do not own it. mmap it */
616                         
617                                 /* this is the usual case on Linux */   
618
619                         mmapAddr = shdr->sh_addr;
620                                 mmapAddr = mmapAddr % pageSize;
621                                 mmapAddr = shdr->sh_addr - mmapAddr;
622
623 #if defined(sparc_sun_solaris2_4)
624                                 checkAddr = checkMap((unsigned long)mmapAddr);
625 #else
626                                 checkAddr = dladdr((void*) mmapAddr, &dlip);
627 #endif
628
629                         mmapAddr =(unsigned long) mmap((void*)mmapAddr ,((*(int*)tmpPtr)+1)*sizeof(unsigned),
630                                 PROT_READ|PROT_WRITE,MAP_FIXED|MAP_PRIVATE,fd,0);
631
632                                 if( mmapAddr == ( shdr->sh_addr - (shdr->sh_addr % pageSize  ) )){ 
633                                         /* set tramp guard to 1 */
634                                         for(i=0;i<*(int*)tmpPtr;i++){
635                                                 ((unsigned*) dataAddress)[i]=1;
636                                         }
637                                 }
638
639                         }else{
640                                 /*      we already own it. 
641                                         this probably means something else is using this memory.
642                                         
643                                         bail out
644                                 */
645
646         
647 #if defined(sparc_sun_solaris2_4)
648
649                                 /* this is the usual case on Solaris */
650                                 
651                                 /* set tramp guard to 1 */
652                                 for(i=0;i<*(int*)tmpPtr;i++){
653                                         ((unsigned*) dataAddress)[i]=1;
654                                 }
655
656 #else
657                                 fprintf(stderr,"ERROR: Could not reload DYNINST_tramp_guards\n\n");
658                                 fprintf(stderr,"terminating .... \n");
659                                 exit(1);
660
661 #endif 
662                                 
663                         
664                         }
665
666                 }else if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_data", 15)) {
667                         elfData = Elf_getdata(scn, NULL);
668                         tmpPtr = elfData->d_buf;
669                         dataAddress = -1;
670                         while( dataAddress != 0 ) { 
671                                 /*tmpPtr may not be aligned on the correct boundry
672                                 so use memcpy to set dataSize
673                                 dataSize = *(int*) tmpPtr;*/
674                                 memcpy((char*) & dataSize, tmpPtr, sizeof(int));
675
676                                 tmpPtr+=sizeof(int);
677                                 memcpy( (char*) & dataAddress, tmpPtr, sizeof(Address));
678
679                                 tmpPtr += sizeof(Address);
680                                 if(dataAddress){
681                                         memcpy((char*) dataAddress, tmpPtr, dataSize);
682
683                                         tmpPtr += dataSize;
684                                 }
685                         }
686
687                 }else if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_",11)){ 
688                         char *tmpStr = strchr((char *)strData->d_buf + shdr->sh_name, (int)'_'); ;
689
690                         tmpStr ++;
691
692 #if defined(sparc_sun_solaris2_4)
693                         if( r_debug_is_set == 0 ) { 
694                                 /* this moved up incase there is no dyninstAPI_### section, map and
695                                 _r_debug are still set correctly. */
696                                 /* solaris does not make _r_debug available by
697                                 default, we have to find it in the _DYNAMIC table */
698
699                                 __Elf_Dyn *_dyn = (__Elf_Dyn*)& _DYNAMIC;       
700                                 while(_dyn && _dyn->d_tag != 0 && _dyn->d_tag != 21){
701                                         _dyn ++;
702                                 }
703                                 if(_dyn && _dyn->d_tag != 0){
704                                         _r_debug = *(struct r_debug*) _dyn->d_un.d_ptr;
705                                 }
706                                 map = _r_debug.r_map;
707                                 r_debug_is_set = 1;
708                         }else{
709                                 map = _r_debug.r_map;
710                         }
711
712 #endif
713                         if( *tmpStr>=0x30 && *tmpStr <= 0x39 ) {
714                                 /* we dont want to do this unless this is a dyninstAPI_### section
715                                         specifically, dont do this for dyninstAPI_SharedLibraries*/
716                                 retVal = 1; /* this is a restored run */
717
718                                 if( *tmpStr>=0x30 && *tmpStr <= 0x39 ) {
719                                         /* this is a heap tramp section */
720
721                                         /*      the new starting address of the heap is immediately AFTER the last
722                                                 dyninstAPI_### section, so we can ALWAYS memcpy the data into place
723                                                 see the value of newHeapAddr in writeBackElf.C
724                                         */
725                                         elfData = Elf_getdata(scn, NULL);
726                                         memcpy((void*)shdr->sh_addr, elfData->d_buf, shdr->sh_size);
727                                 }
728                         }
729                 }
730                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_mutatedSO")){
731                         /* make sure the mutated SOs are loaded, not the original ones */
732                         char *soNames;
733                         int mutatedFlag = 0;
734                         int totallen=0;
735                         __Elf_Dyn *_dyn = (__Elf_Dyn*)& _DYNAMIC;       
736 #if defined(sparc_sun_solaris2_4)
737                         Link_map *lmap=0;
738 #elif defined(i386_unknown_linux2_0) \
739    || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
740                         struct link_map *lmap=0;
741 #endif
742                         char *loadedname, *dyninstname;
743
744                         elfData = Elf_getdata(scn, NULL);
745
746                         sharedLibraryInfo = (char*) malloc(elfData->d_size);
747                         memcpy(sharedLibraryInfo, elfData->d_buf, elfData->d_size);
748                         lmap = _r_debug.r_map;
749
750                         for(soNames = (char*) elfData->d_buf ; totallen<elfData->d_size; 
751                                 soNames = &((char*) elfData->d_buf)[strlen(soNames)+1+sizeof(unsigned int) +sizeof(unsigned int)]){
752                                 /* added a +sizeof(unsigned int) above for flag */
753                                 totallen += strlen(soNames) + 1 + sizeof(unsigned int) +sizeof(unsigned int); /*for flag*/
754                                 memcpy(&mutatedFlag, &((char*) elfData->d_buf)[totallen-sizeof(unsigned int)], sizeof(unsigned int));
755                                 lmap = _r_debug.r_map;
756                                 while(lmap){
757                                         loadedname = strrchr(lmap->l_name,'/');
758                                         dyninstname =  strrchr((const char *)soNames,(int)'/');
759                                         if(loadedname == 0){
760                                                 loadedname = lmap->l_name;
761                                         }
762                                         if(dyninstname == 0){
763                                                 dyninstname = soNames;
764                                         }       
765                                         if(mutatedFlag && !strcmp(loadedname, dyninstname)) {
766                                                 if(!checkSO(lmap->l_name)){
767                         printf("ERROR: %s was mutated during saveworld and",lmap->l_name);
768                         printf(" the currently loaded %s has not been mutated\n", lmap->l_name);
769                         printf(" check your LD path to be sure the mutated %s is visible\n", soNames);
770                                                         soError = 1;
771                 
772                                                 }
773
774                 
775                                         }
776                                         lmap = lmap->l_next;
777                                 }
778                         }
779                 }
780                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "rtlib_addr")){
781                         unsigned int ptr;
782                         int foundLib = 0, result;
783                         int done = 0;
784
785
786                         elfData = Elf_getdata(scn, NULL);
787
788                         /*ptr = elfData->d_buf;*/
789                         /* use memcpy because of alignment issues on sparc */   
790                         memcpy(&ptr,elfData->d_buf,sizeof(unsigned int));
791
792 #if defined(sparc_sun_solaris2_4)
793                         if( r_debug_is_set == 0 ) {
794                                 /* this moved up incase there is no dyninstAPI_### section, map and
795                                         _r_debug are still set correctly. */
796                                 /* solaris does not make _r_debug available by
797                                         default, we have to find it in the _DYNAMIC table */
798
799                                 __Elf_Dyn *_dyn = (__Elf_Dyn*)& _DYNAMIC;
800                                 while(_dyn && _dyn->d_tag != 0 && _dyn->d_tag != 21){
801                                         _dyn ++;
802                                 }
803                                 if(_dyn && _dyn->d_tag != 0){
804                                         _r_debug = *(struct r_debug*) _dyn->d_un.d_ptr;
805                                 }
806                                 map = _r_debug.r_map;
807                                 r_debug_is_set = 1;
808                         }else{
809                                 map = _r_debug.r_map;
810                         }
811 #endif
812         
813                         map = _r_debug.r_map;
814
815                         while(map && !done){
816                                 /*fprintf(stderr,"CHECKING %s 0x%x\n", map->l_name,map->l_addr);*/
817                                 if( * map->l_name  && strstr(map->l_name, "libdyninstAPI_RT")){
818                                         unsigned long loadaddr = (unsigned long)map->l_addr;
819
820                                         /*      LINUX PROBLEM. in the link_map structure the map->l_addr field is NOT
821                                                 the load address of the dynamic object, as the documentation says.  It is the
822                                                 RELOCATED address of the object. If the object was not relocated then the
823                                                 value is ZERO.
824
825                                                 So, on LINUX we check the address of the dynamic section, map->l_ld, which is
826                                                 correct.
827                                         */
828 #if defined(i386_unknown_linux2_0) || defined(x86_64_unknown_linux2_4)
829                                         loadaddr = (unsigned long)map->l_ld;
830 #endif
831
832                                         /*fprintf(stderr," loadadd %x ptr %x\n", loadaddr, ptr);*/
833                                         if( loadaddr !=  (ptr)){
834                                                 fixInstrumentation(map->l_name, loadaddr,  (ptr));
835                                         }
836                                 }
837                                 /* check every loaded SO but leave map such that map->l_next == NULL.
838                                         The next time a SO is loaded it will be placed at 
839                                         map->l_next, so keep a tail pointer such that we 
840                                         dont need to loop through the entire list again
841                                 */
842                                 if(map->l_next){
843                                         map = map->l_next;
844                                 }else{
845                                         done = 1;
846                                 }
847                         }
848                 }
849                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_SharedLibraries")){
850                         unsigned long diffAddr;
851                         unsigned long ld_linuxBaseAddr, baseAddr, size;
852 #if defined(sparc_sun_solaris2_4)
853                         unsigned int *overWriteInsn;
854                         unsigned int *pltEntry, *PLTEntry, *dyninst_jump_templatePtr, pltInsn, tmpAddr;
855                         unsigned int BA_MASK=0x30800000;
856                         unsigned int BA_IMM=0x003fffff;
857                         unsigned int SETHI_IMM=0x003fffff;
858                         unsigned int JMP_IMM =0x00001fff;
859                         unsigned int offset, callInsn;
860                         struct sigaction  mysigact, oldsigact;
861 #endif
862                         char *ptr;
863                         int foundLib = 0, result;
864                         int done = 0;
865
866
867                         elfData = Elf_getdata(scn, NULL);
868
869                         ptr = elfData->d_buf;
870                 
871                         map = _r_debug.r_map;
872
873                         while(map && !done){
874                                 if( * map->l_name ){
875                                         unsigned int loadaddr = map->l_addr;
876
877                                         /*      LINUX PROBLEM. in the link_map structure the map->l_addr field is NOT
878                                                 the load address of the dynamic object, as the documentation says.  It is the
879                                                 RELOCATED address of the object. If the object was not relocated then the
880                                                 value is ZERO.
881
882                                                 So, on LINUX we check the address of the dynamic section, map->l_ld, which is
883                                                 correct.
884                                         */
885 #if defined(i386_unknown_linux2_0) || defined(x86_64_unknown_linux2_4)
886                                         loadaddr = (unsigned long)map->l_ld;
887 #endif
888
889                                         /*fprintf(stderr," CHECKING: %s %x\n",map->l_name, map->l_addr);*/
890                                         diffAddr = checkSOLoadAddr(map->l_name, loadaddr);
891                                         if(diffAddr){
892                                                 fixInstrumentation(map->l_name, loadaddr, diffAddr);
893                                         }
894 #if defined(i386_unknown_linux2_0) \
895  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
896                                         /* ld-linux.so will never be hand relocated so l_addr should be correct. right? */
897                                         if(strstr(map->l_name, "ld-linux.so")){
898                                                 ld_linuxBaseAddr = map->l_addr;
899                                         }       
900 #endif
901                                 }
902                                 /* check every loaded SO but leave map such that map->l_next == NULL.
903                                         The next time a SO is loaded it will be placed at 
904                                         map->l_next, so keep a tail pointer such that we 
905                                         dont need to loop through the entire list again
906                                 */
907                                 if(map->l_next){
908                                         map = map->l_next;
909                                 }else{
910                                         done = 1;
911                                 }
912                         }
913                         if( shdr->sh_addr != 0){
914                                 /* if the addr is zero, then there is 
915                                         no PLT entry for dlopen.  if there is
916                                         no entry for dlopen the mutatee must not
917                                         call it.  -- what about calling it from
918                                         a shared lib that is statically loaded?
919                                 */
920
921                         /* WHY IS THERE A POUND DEFINE HERE? 
922
923                                 well, we need to intercept the dlopen calls from the mutated binary
924                                 because our trampolines expect the shared libraries to be in
925                                 a particular location and if they are not where they are expected
926                                 our trampolines can jump off into nothingness, or even worse, some
927                                 random bit of executable code.  
928
929                                 So we must intercept the dlopen call and then check to be sure
930                                 the shared libraries are loaded in the same place as before.  If
931                                 they are not we exit with a message to the user saying this is
932                                 a fatal error.
933                 
934                                 Note, only shared libraries that have been instrumented are checked
935                                 here.  
936                         */
937
938 #if defined(sparc_sun_solaris2_4) 
939                         /* 
940                                 For a description of what is going on here read
941                                 the comment in dyninst_jump_template above.
942
943                                 This code generated all the instructions refered
944                                 to in that comment as "GENERATED BELOW".
945
946                         */
947
948                         pltEntry = (unsigned int*) shdr->sh_addr;
949                         pltInsn = *pltEntry; /* save insn for later */
950                         pltEntry += 1;
951
952                         /* The PLT entry may look like:
953                                 sethi
954                                 ba,a
955                                 nop
956
957                            or
958                         
959                                 sethi
960                                 sethi
961                                 jmp
962
963                         */
964                         if( (*pltEntry & (BA_MASK)) == (BA_MASK) ){
965                                 /* we have the sethi/ba,a/nop type */
966
967                                 offset = (*pltEntry) & BA_IMM;
968                                 if(offset & 0x00200000){
969                                         /* negative so sign extend */
970                                         offset = 0xffc00000 | offset;
971                                 }
972                                 PLTEntry = pltEntry;
973                         
974                                 PLTEntry += (offset*4)/sizeof(PLTEntry); /* move PLTEntry offset*4 bytes!*/
975
976                         }else{
977                                 /* we have the sethi/sethi/jmp type */
978                                 tmpAddr = ((*pltEntry) & SETHI_IMM)<<10;
979                                 pltEntry ++;
980                                 tmpAddr += ((*pltEntry) & JMP_IMM);
981                                 PLTEntry = tmpAddr;
982                                 pltEntry --;
983                         }
984
985                         dyninst_jump_templatePtr = (unsigned int*) & __dyninst_jump_template__;
986
987                         baseAddr = ((unsigned int) dyninst_jump_templatePtr)  -
988                                 ( ((unsigned int) dyninst_jump_templatePtr)% getpagesize());
989                         size =  (unsigned int) dyninst_jump_templatePtr  - baseAddr + 80;
990                         result = mprotect((void*)baseAddr , size, 
991                            PROT_READ|PROT_WRITE|PROT_EXEC);
992
993                         /* build sethi hi(register_o7), %g1 */
994                         *dyninst_jump_templatePtr = 0x03000000;
995                         *dyninst_jump_templatePtr |= ( (((unsigned int ) & register_o7)& 0xfffffc00) >> 10); /*0xffffe000 */
996
997                         dyninst_jump_templatePtr ++;
998
999                         /* build st %o7, &register_o7 */
1000                         *dyninst_jump_templatePtr = 0xde206000;
1001                         *dyninst_jump_templatePtr |=  ( ((unsigned int ) & register_o7) & 0x000003ff ); /*0x00001fff*/
1002
1003                         dyninst_jump_templatePtr ++;
1004
1005                         /* build call PLTEntry */
1006                         *dyninst_jump_templatePtr = 0x40000000;
1007                         *dyninst_jump_templatePtr |= ( ((unsigned int) (PLTEntry)-  ((unsigned int) dyninst_jump_templatePtr)) >>2);
1008                         dyninst_jump_templatePtr ++;
1009
1010                         /* copy from plt */
1011                         *dyninst_jump_templatePtr = pltInsn;
1012                         dyninst_jump_templatePtr ++;
1013
1014
1015                         /* advance past call to pseudoSigHandler */
1016                         dyninst_jump_templatePtr = (unsigned int*) &__dyninst_jump_template__done__ ;
1017         
1018                         /* build sethi hi(register_o7), %g1 */
1019                         *dyninst_jump_templatePtr = 0x03000000;
1020                         *dyninst_jump_templatePtr |= ( (((unsigned int ) & register_o7)& 0xfffffc00) >> 10); /*0xffffe000*/
1021
1022                         dyninst_jump_templatePtr ++;
1023
1024                         /* build ld %o7, register_o7 */
1025                         *dyninst_jump_templatePtr = 0xde006000;
1026                         *dyninst_jump_templatePtr |=  ( ((unsigned int ) & register_o7) & 0x000003ff );  /*0x00001fff*/
1027
1028
1029                         /* THIS ENABLES THE JUMP */
1030                         /* edit plt to jump to __dyninst_jump_template__ */
1031                         baseAddr = ((unsigned int) pltEntry)  -
1032                                 ( ((unsigned int) pltEntry)% getpagesize());
1033                         size =  (unsigned int) pltEntry  - baseAddr + 8;
1034                         result = mprotect((void*)baseAddr , size,
1035                            PROT_READ|PROT_WRITE|PROT_EXEC);
1036
1037                         /* build sethi hi(&__dyninst_jump_template__), %g1 */
1038                         pltEntry --;
1039                         *pltEntry = 0x03000000;
1040                         *pltEntry |= ( (((unsigned int ) &__dyninst_jump_template__) )>> 10);
1041                         pltEntry ++;
1042         
1043                         /* build jmpl %g1, %r0 */       
1044                         *pltEntry = 0x81c06000;
1045                         *pltEntry |=  ( ((unsigned int ) &__dyninst_jump_template__ ) & 0x00003ff );
1046
1047                         pltEntry ++;
1048                         *pltEntry = 0x01000000;
1049 #elif defined(i386_unknown_linux2_0) \
1050    || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
1051                         /* install jump to catch call to _dl_debug_state */
1052                         /* see comment int hack_ld_linux_plt for explainations */
1053                         hack_ld_linux_plt(ld_linuxBaseAddr + shdr->sh_addr); 
1054 #endif
1055                 }/* shdr->sh_addr != 0 */ 
1056                 }
1057                 if( !strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPIhighmem_",18)){
1058                         /*the layout of dyninstAPIhighmem_ is:
1059                         pageData
1060                         address of update
1061                         size of update
1062                         ...     
1063                         address of update
1064                         size of update  
1065                         number of updates
1066         
1067                         we must ONLY overwrite the updates, the other
1068                         areas of the page may be important (and different than
1069                         the saved data in the file.  we first copy out the
1070                         page, the apply the updates to it, and then
1071                         write it back.
1072                         */
1073
1074                         int oldPageDataSize;
1075                         int count =0;
1076
1077                         retVal = 1; /* just to be sure */
1078                         elfData = Elf_getdata(scn, NULL);
1079                         numberUpdates = 0;
1080                         
1081                         /*this section may be padded out with zeros to align the next section
1082                           so we need to look backwards until we find a nonzero value */
1083                         while(numberUpdates == 0){
1084                                 count++;
1085                                 numberUpdates = (unsigned int) ( ((unsigned int*) elfData->d_buf)[
1086                                         (elfData->d_size - (sizeof(unsigned int)*count))/ sizeof(unsigned int) ]);
1087                         }
1088
1089                         /*fprintf(stderr," numberUpdates: %d :: (%d - 4) / 4  %x\n", numberUpdates, elfData->d_size, (unsigned int*) &elfData->d_buf );*/
1090
1091                         oldPageDataSize = shdr->sh_size-(((2*numberUpdates)* sizeof(unsigned int)) +((sizeof(unsigned int)*count))) ;
1092
1093
1094                         oldPageData = (char*) malloc(oldPageDataSize+sizeof(unsigned long));
1095                         /*fprintf(stderr,"oldpagedatasize %d datasize %d\n",oldPageDataSize,elfData->d_size);*/
1096                         /*copy old page data */
1097
1098
1099                         /* probe memory to see if we own it */
1100 #if defined(sparc_sun_solaris2_4)
1101
1102                         /* dladdr does not work here with all patchlevels of solaris 2.8
1103                            so we use the /proc file system to read in the /proc/pid/map file
1104                            and determine for our selves if the memory belongs to us yet or not*/
1105                         findMap();
1106                         checkAddr = checkMap((unsigned long)shdr->sh_addr);
1107 #else
1108                         checkAddr = dladdr((void*)shdr->sh_addr, &dlip);
1109 #endif
1110
1111
1112                         updateSize  = shdr->sh_size-((2*numberUpdates)* (sizeof(unsigned int)) -(count* (sizeof(unsigned int))));
1113                         /*fprintf(stderr," updateSize : %d-((2 * %d + 1) * 4))",shdr->sh_size, numberUpdates);*/
1114         
1115                         if(!checkAddr){ 
1116                                 /* we dont own it,mmap it!*/
1117
1118                                 mmapAddr = shdr->sh_offset;
1119                                 mmapAddr =(unsigned long) mmap((void*) shdr->sh_addr,oldPageDataSize,
1120                                         PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_PRIVATE,fd,mmapAddr);
1121                                         /*fprintf(stderr,"MMAP %x %d %x size: %x\n",shdr->sh_addr, mmapAddr,shdr->sh_offset,oldPageDataSize);*/
1122                                         
1123
1124                         }else{
1125                                 /*we own it, finish the memcpy */
1126                                 mmapAddr = (unsigned long) memcpy((void*) oldPageData, 
1127                                       (const void*) shdr->sh_addr, oldPageDataSize);
1128                                 /*fprintf(stderr,"memcpy %x %d\n",shdr->sh_addr, updateSize);*/
1129
1130                         }
1131
1132                         dataPtr =(unsigned long *) &(((char*)  elfData->d_buf)[oldPageDataSize]);       
1133                         /*apply updates*/
1134                         for(i = 0; i< numberUpdates; i++){
1135                                 updateAddress = *dataPtr; 
1136                                 updateSize = *(++dataPtr);
1137
1138                                 updateOffset = updateAddress - shdr->sh_addr;
1139                                 /*do update*/   
1140                                 /*fprintf(stderr,"updateAddress %x : %x %x %d %d\n",updateAddress,&( oldPageData[updateOffset]), &(((char*)elfData->d_buf)[updateOffset]) , updateSize,updateOffset);*/
1141                                 memcpy(&( oldPageData[updateOffset]),
1142                                                 &(((char*)elfData->d_buf)[updateOffset]) , updateSize); 
1143
1144                                 dataPtr ++;
1145
1146                         
1147                         } 
1148                         if(!checkAddr){
1149                                 mmapAddr = shdr->sh_offset ;
1150
1151                                 mmapAddr =(unsigned long) mmap((void*) shdr->sh_addr,oldPageDataSize, 
1152                                         PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED| MAP_PRIVATE,fd,mmapAddr);
1153
1154                                         /*fprintf(stderr,"2MMAP %x %d\n",shdr->sh_addr, mmapAddr);*/
1155
1156
1157                         }else{
1158
1159                                 memcpy((void*) shdr->sh_addr, oldPageData,oldPageDataSize );
1160                                 /*fprintf(stderr,"2memcpy %x %d\n",shdr->sh_addr, oldPageDataSize);*/
1161
1162                         }
1163                 }
1164                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_loadLib")){
1165                         /* ccw 14 may 2002 */
1166                         /* this section loads shared libraries into the mutated binary
1167                                 that were loaded by BPatch_thread::loadLibrary */
1168                         void * handle =NULL;
1169                         Dl_info p;
1170                         unsigned long loadAddr;
1171                         elfData = Elf_getdata(scn, NULL);
1172                         tmpPtr = elfData->d_buf;
1173
1174                         while(*tmpPtr) { 
1175                                 handle = dlopen(tmpPtr, RTLD_LAZY);
1176                                 if(handle){
1177                                         dlinfo(handle, RTLD_DI_CONFIGADDR,(void*) &p);
1178 #if defined(sparc_sun_solaris2_4)
1179                                         loadAddr = checkSOLoadAddr(tmpPtr,(unsigned long)p.dli_fbase);
1180                                         if(loadAddr){
1181                                                 fixInstrumentation(tmpPtr,(unsigned long)p.dli_fbase, loadAddr);
1182                                         }
1183 #endif
1184
1185                                 }else{
1186
1187                                         printf(" %s cannot be loaded at the correct address\n", tmpPtr );
1188                                         printf(" This is an unrecoverable error, the instrumentation will not");
1189                                         printf("\n run correctly if shared libraries are loaded at a different address\n");
1190                                         printf("\n Exiting.....\n");
1191
1192                                         printf("\n%s\n",dlerror());
1193                                         fflush(stdout);
1194                                         exit(9);
1195
1196                                 }
1197                                 /* brk ptr not used for ELF */
1198                                 tmpPtr += (strlen(tmpPtr) +1 + sizeof(void *)); 
1199
1200                         }
1201
1202                 }
1203         }
1204 #if defined(sparc_sun_solaris2_4)
1205
1206         if(procMemMap){
1207                 free(procMemMap);
1208         }
1209 #endif
1210
1211         Elf_end(elf);
1212         close(fd);
1213
1214         free(execStr);
1215
1216         if(soError){
1217                 exit(2);
1218         }
1219         return retVal;
1220 }
1221 /* vim:set ts=5: */