This commit fixes a small bug in save the world.
[dyninst.git] / dyninstAPI_RT / src / RTmutatedBinary.c
1 /* $Id: RTmutatedBinary.c,v 1.2 2002/05/09 19:16:28 chadd Exp $ */
2
3 /* this file contains the code to restore the necessary
4    data for a mutated binary 
5  */
6
7
8 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
9 #include <unistd.h>
10 #include  <fcntl.h>
11
12 #if defined(sparc_sun_solaris2_4)
13 #include  <libelf.h>
14 #elif defined(i386_unknown_linux2_0)
15 #include <libelf/libelf.h>
16 #define __USE_GNU
17 #endif
18
19 #include <sys/mman.h>
20 #include <dlfcn.h>
21 #include <link.h> /* ccw 23 jan 2002 */
22 #if defined(sparc_sun_solaris2_4) 
23 #include <sys/link.h>
24 #include <signal.h>
25 #endif
26 #include <limits.h>
27
28 #if defined(sparc_sun_solaris2_4)
29 extern void* _DYNAMIC;
30 #elif defined(i386_unknown_linux2_0)
31 extern ElfW(Dyn) _DYNAMIC[];
32
33 #endif
34 typedef struct {
35       Elf32_Sword d_tag;
36       union {
37           Elf32_Sword d_val;
38           Elf32_Addr d_ptr;
39       } d_un;
40   } __Elf32_Dyn;
41
42
43
44 unsigned int checkAddr;
45 int isElfFile=0;
46 char *buffer;
47 struct link_map* map;
48 unsigned int dl_debug_state_addr;
49
50 #if defined(sparc_sun_solaris2_4)
51 struct r_debug _r_debug; /* ccw 2 apr 2002 */
52 extern unsigned int _dyninst_call_to_dlopen;
53 extern unsigned int __dyninst_jump_template__;
54 extern unsigned int __dyninst_jump_template__done__;
55 #endif
56
57 char *sharedLibraryInfo = NULL;
58 unsigned int originalInsnBkpt;
59 unsigned int addressBkpt;
60
61 /*      this is not misnamed.  In the future, this function will contain
62         code to patch the instrumentation of a shared library that has 
63         been loaded into a different place during a mutated binary run.
64
65         Now, it just exit()s, as you can see
66 */
67
68 void fixInstrumentation(char* soName, unsigned int currAddr, unsigned int oldAddr){
69         printf(" %s loaded at wrong address: 0x%x (expected at 0x%x) \n", soName, currAddr, oldAddr);
70         printf(" This is an unrecoverable error, the instrumentation will not");
71         printf("\n run correctly if shared libraries are loaded at a different address\n");
72         printf("\n Exiting.....\n");
73         fflush(stdout);
74         exit(9);
75 }
76
77 /*      this function checks the shared library (soName) to see if it
78         is currently loaded (loadAddr) at the same place it was before (address).
79         If the shared library is not found in the list (sharedLibraryInfo) that
80         mean the shared library was *NOT* instrumented and can be loaded
81         anywhere
82 */
83 unsigned int checkSOLoadAddr(char *soName, unsigned int loadAddr){
84         unsigned int result=0, found = 0;
85         unsigned int address;
86         char *ptr = sharedLibraryInfo;
87         while(ptr &&  *ptr && !found ){
88                 if(strstr(soName, ptr)){
89                         found = 1;
90                         ptr += (strlen(ptr) +1);
91                         memcpy(&address, ptr, sizeof(unsigned int)); 
92                         /* previous line is done b/c of alignment issues on sparc*/
93                         if(loadAddr == address) {
94                                 result = 0;
95                         }else{
96                                 result = address;
97                         }       
98                 }
99
100                 ptr += (strlen(ptr) +1);
101                 ptr += sizeof(unsigned int);
102
103         }
104         if(!found){
105                 result = 0;
106         }
107         return result;
108 }
109 #if defined(sparc_sun_solaris2_4)
110 unsigned int register_o7;
111
112 unsigned int loadAddr;
113 /*      this function is not a signal handler. it was originally but now is 
114         not, it is called below in dyninst_jump_template
115 */ 
116 void pseudoSigHandler(int sig){
117
118         if(_r_debug.r_state == 0){
119                 do{
120                         if(map->l_next){
121                                 map = map->l_next;
122                         }
123                         loadAddr = checkSOLoadAddr(map->l_name, map->l_addr);
124                         if(loadAddr){
125                                 fixInstrumentation(map->l_name, map->l_addr, loadAddr);
126                         }
127
128                 }while(map->l_next);
129
130         }
131 }
132
133 unsigned int loadAddr;
134 void dyninst_jump_template(){
135 /* THE PLAN:
136
137         The Solaris loader/ELF file works as follows:
138         
139         A call to dlopen jumps to the Procedure Linking Table 
140         slot holding the dlopen information.  This slot consists of
141         three instructions:
142         
143         sethi r1, 0xb4
144         ba (to another PLT slot)
145         nop
146
147         The second PLT slot contains three instructions:
148         save
149         call (address of dlopen)
150         nop
151
152         dlopen returns directly to where it was called from, not to
153         either of the PLT slots.  The address from which it was called
154         is located in %o7 when the call to dlopen in the second PLT
155         slot is made. dlopen returns to %o7 +4.
156         
157
158         What our code does:
159
160         The goals is to intercept this call to dlopen by overwritting
161         the first PLT slot to jump to __dyninst_jump_template__ then we
162         can jump to code that will check the addresses of the loaded
163         shared libraries.
164
165         first we must preserver %o7 so we know where to go back to.
166         This is done with the first two instructions in __dyninst_jump_template__
167         These are written as nops BUT are overwritten in the SharedLibraries 
168         branch in checkElfFile.  %o7 is saved in register_o7 declared above.
169         This address is not available until run time so we generate these
170         instructions on the fly.
171
172         Next, we CALL the second PLT slot as normal.  We use the delay
173         slot to run the sethi instruction from the first PLT slot. These
174         instructions are generated at runtime. 
175
176         dlopen will eventually be called and will return to the nop after
177         the sethi.  Now we need to call our function to check the
178         shared library address.  This is pseudoSigHandler.  We must
179         preserve the data returned by dlopen so we do a save to
180         push the register onto the stack before we call our function.
181         We call our function, and then do a restore to retreive the 
182         saved information.
183
184         At __dyninst_jump_template__done__ we want to restore the
185         value in register_o7 to %o7 so when we do a retl we will
186         jump back to where the mutated binary originally called 
187         dlopen.
188         The sethi and ld instructions are generated on the fly just
189         as the first sethi and st pair that saved the value of %o7.
190         The retl used %o7 to jump back to the original place 
191         the mutatee called dlopen. We are done. Whew.
192
193         Note that I know the address of the first PLT slot because
194         the mutator found it and saved it in the mutated binary.
195         The address of the second PLT slot is determined by looking
196         at the instructions in the first PLT slot.
197 */
198         
199
200         asm("nop");
201         asm("__dyninst_jump_template__:");
202
203         asm("nop");     /*sethi hi(register_o7), %g1 GENERATED BELOW*/
204         asm("nop");     /*st %o7 GENERATED BELOW*/
205         asm("nop");     /*call plt GENERATED BELOW*/
206         asm("nop");     /*sethi r1, b4 GENERATED BELOW*/
207
208         asm("nop");
209         asm("save %sp, -104, %sp");
210         asm("nop");
211         pseudoSigHandler(0);
212         asm("nop");
213         asm("restore");
214         asm("nop");
215         asm("nop");
216         asm("__dyninst_jump_template__done__:");
217         asm("nop");     /*sethi hi(register_o7), %g1 GENERATED BELOW*/
218         asm("nop");     /* ld [register_o7], %o7 GENERATED BELOW*/
219         asm("retl");
220
221         asm("nop");     /* this will be filled in below */
222         asm("nop");
223
224 }
225
226 #endif
227
228 #if defined(i386_unknown_linux2_0)
229 unsigned int loadAddr;
230 void dyninst_dl_debug_state(){
231         asm("nop");
232         if(_r_debug.r_state == 1){
233         do {
234                         if(map->l_next){
235                                 map = map->l_next;
236                         }
237                         loadAddr = checkSOLoadAddr(map->l_name, map->l_addr);
238                         if(loadAddr){
239                                 fixInstrumentation(map->l_name, map->l_addr, loadAddr);
240                         }
241                 }while(map->l_next);
242
243         }
244
245         /* the following call is used to call
246          * _dl_debug_state to ensure correctness (if
247          * someone relies on it being called it is
248          * execuated after this function)
249          * The value stored in dl_debug_state_addr is
250          * the address of the function _dl_debug_state
251          * and is set in checkElfFile
252          */
253         asm("nop");
254         asm("nop");
255         asm("nop");
256         asm("call *dl_debug_state_addr");
257         asm("nop");
258
259 }
260
261 void hack_ld_linux_plt(unsigned int pltEntryAddr){ 
262 /* this is ugly.
263  * save the world needs to check each shared library
264  * that is loaded to ensure that it is loaded at the
265  * same base address it was loaded at when the mutator/mutatee
266  * pair ran.  
267  * So, we know dlopen calls _dl_debug_state per the r_debug
268  * interface to let the process know a shared library has changed
269  * state.
270  * with this function we change the Procedure Linkage Table (.plt)
271  * for ld-linux.so so that the entry that used to point to
272  * _dl_debug_state points to dyninst_dl_debug_state.
273  *
274  * dyninst_dl_debug_state then calls _dl_debug_state before
275  * exiting 
276  *
277  * dont try this at home
278  */
279         unsigned int mprotectAddr = pltEntryAddr - (pltEntryAddr % getpagesize());      
280         unsigned int newTarget = (unsigned int) &dyninst_dl_debug_state ;
281         
282         mprotect( (void*) mprotectAddr, pltEntryAddr - mprotectAddr + 4, 
283                                 PROT_READ|PROT_WRITE|PROT_EXEC);
284
285         memcpy( (void*) &dl_debug_state_addr, (void*) pltEntryAddr, 4); 
286
287         memcpy( (void*) pltEntryAddr, &newTarget, 4);
288 }
289 #endif
290
291
292 int checkSO(char* soName){
293         Elf32_Shdr *shdr;
294         Elf32_Ehdr *   ehdr;
295         Elf *          elf;
296         int       fd;
297         Elf_Data *strData;
298         Elf_Scn *scn;
299         int result = 0;
300
301         if((fd = (int) open(soName, O_RDONLY)) == -1){
302                 RTprintf("cannot open : %s\n",soName);
303                 fflush(stdout); 
304                 return;
305         }
306         if((elf = elf_begin(fd, ELF_C_READ, NULL)) ==NULL){
307                 RTprintf("%s %s \n",soName, elf_errmsg(elf_errno()));
308                 RTprintf("cannot elf_begin\n");
309                 fflush(stdout);
310                 close(fd);
311                 return;
312         }
313
314         ehdr = elf32_getehdr(elf);
315         scn = elf_getscn(elf, ehdr->e_shstrndx);
316         strData = elf_getdata(scn,NULL);
317         for( scn = NULL; !result && (scn = elf_nextscn(elf, scn)); ){
318                 shdr = elf32_getshdr(scn);
319                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, ".dyninst_mutated")) {
320                         result = 1;
321                 }
322         }
323         elf_end(elf);
324         close(fd);
325
326         return result;
327 }
328
329 int checkElfFile(){
330
331
332         Elf32_Shdr *shdr;
333         Elf32_Ehdr *   ehdr;
334         Elf *          elf;
335         int       cnt,fd;
336         Elf_Data *elfData,*strData;
337         Elf_Scn *scn;
338         char execStr[256];
339         int retVal = 0, result;
340         unsigned int mmapAddr;
341         int pageSize;
342         Address dataAddress;
343         int dataSize;
344         char* tmpPtr;
345         unsigned int updateAddress, updateSize, updateOffset;
346         unsigned int *dataPtr;
347         unsigned int numberUpdates,i ;
348         char* oldPageData;
349         Dl_info dlip;
350         int soError = 0; 
351         int sawFirstHeapTrampSection = 0;
352         elf_version(EV_CURRENT);
353
354 #if defined(sparc_sun_solaris2_4)
355         sprintf(execStr,"/proc/%d/object/a.out",getpid());
356 #elif defined(i386_unknown_linux2_0)
357         sprintf(execStr,"/proc/%d/exe",getpid());
358 #endif
359
360         if((fd = (int) open(execStr, O_RDONLY)) == -1){
361                 printf("cannot open : %s\n",execStr);
362                 fflush(stdout); 
363                 return;
364         }
365         if((elf = elf_begin(fd, ELF_C_READ, NULL)) ==NULL){
366                 printf("%s %s \n",execStr, elf_errmsg(elf_errno()));
367                 printf("cannot elf_begin\n");
368                 fflush(stdout);
369                 close(fd);
370                 return;
371         }
372
373         ehdr = elf32_getehdr(elf);
374         scn = elf_getscn(elf, ehdr->e_shstrndx);
375         strData = elf_getdata(scn,NULL);
376         pageSize =  getpagesize();
377         for(cnt = 0, scn = NULL; !soError &&  (scn = elf_nextscn(elf, scn));cnt++){
378                 shdr = elf32_getshdr(scn);
379                 if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_data", 15)) {
380                         elfData = elf_getdata(scn, NULL);
381                         tmpPtr = elfData->d_buf;
382                         dataAddress = -1;
383                         while( dataAddress != 0 ) { 
384                                 dataSize = *(int*) tmpPtr;
385                                 tmpPtr+=sizeof(int);
386                                 dataAddress = *(Address*) tmpPtr;
387                                 tmpPtr += sizeof(Address);
388                                 if(dataAddress){
389                                         memcpy((char*) dataAddress, tmpPtr, dataSize);
390                                         tmpPtr += dataSize;
391                                 }
392                         }
393
394                 }else if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_",11)){
395                         char *tmpStr;
396 #if defined(sparc_sun_solaris2_4)
397                         /* solaris does not make _r_debug available by
398                                 default, we have to find it in the 
399                                 _DYNAMIC table */
400
401                         __Elf32_Dyn *_dyn = (__Elf32_Dyn*)& _DYNAMIC;   
402
403                         while(_dyn && _dyn->d_tag != 0 && _dyn->d_tag != 21){
404                                 _dyn ++;
405                         }
406                         if(_dyn && _dyn->d_tag != 0){
407                                 _r_debug = *(struct r_debug*) _dyn->d_un.d_ptr;
408                         }
409                         map = _r_debug.r_map;
410
411 #endif
412                         retVal = 1; /* this is a restored run */
413                         tmpStr = strchr((char *)strData->d_buf + shdr->sh_name,'_'); 
414                         tmpStr ++;
415                         if( *tmpStr>=0x30 && *tmpStr <= 0x39 ) {
416                                 /* this is a heap tramp section */
417                                 if( sawFirstHeapTrampSection ){
418                                         result = mmap((void*) shdr->sh_addr, shdr->sh_size, 
419                                         PROT_READ|PROT_WRITE|PROT_EXEC,
420                                         MAP_FIXED|MAP_PRIVATE,fd,shdr->sh_offset);
421                                 }else{
422                                         elfData = elf_getdata(scn, NULL);
423                                         memcpy((void*)shdr->sh_addr, elfData->d_buf, shdr->sh_size);
424                                         sawFirstHeapTrampSection = 1;
425                                 }
426                         }
427                 }
428                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_mutatedSO")){
429                         /* make sure the mutated SOs are loaded, not the original ones */
430                         char *soNames;
431                         int totallen=0;
432                         __Elf32_Dyn *_dyn = (__Elf32_Dyn*)& _DYNAMIC;   
433 #if defined(sparc_sun_solaris2_4)
434                         Link_map *lmap=0;
435 #elif defined(i386_unknown_linux2_0)
436                         struct link_map *lmap=0;
437 #endif
438                         char *loadedname, *dyninstname;
439
440                         elfData = elf_getdata(scn, NULL);
441
442                         sharedLibraryInfo = (char*) malloc(elfData->d_size);
443                         memcpy(sharedLibraryInfo, elfData->d_buf, elfData->d_size);
444                         lmap = _r_debug.r_map;
445                 
446                         for(soNames = (char*) elfData->d_buf ; totallen<elfData->d_size; 
447                                 soNames = &((char*) elfData->d_buf)[strlen(soNames)+1+sizeof(unsigned int)] ){
448                                 totallen += strlen(soNames) + 1 + sizeof(unsigned int);
449                                 lmap = _r_debug.r_map;
450                                 while(lmap){
451                                         loadedname = strrchr(lmap->l_name,'/');
452                                         dyninstname =  strrchr(soNames,'/');
453                                         if(loadedname == 0){
454                                                 loadedname = lmap->l_name;
455                                         }
456                                         if(dyninstname == 0){
457                                                 dyninstname = soNames;
458                                         }       
459                                         if(!strcmp(loadedname, dyninstname)) {
460                                                 if(!checkSO(lmap->l_name)){
461                         printf("ERROR: %s was mutated during saveworld and",lmap->l_name);
462                         printf(" the currently loaded %s has not been mutated\n", lmap->l_name);
463                         printf(" check your LD path to be sure the mutated %s is visible\n", soNames);
464                                                         soError = 1;
465                 
466                                                 }
467
468                 
469                                         }
470                                         lmap = lmap->l_next;
471                                 }
472                         }
473                 }
474                 if(!strcmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPI_SharedLibraries")){
475                         unsigned int diffAddr;
476                         unsigned int ld_linuxBaseAddr, baseAddr, size;
477 #if defined(sparc_sun_solaris2_4)
478                         unsigned int *overWriteInsn;
479                         unsigned int *pltEntry, *PLTEntry, *dyninst_jump_templatePtr, pltInsn;
480                         unsigned int BA_MASK = 0x003fffff;
481                         unsigned int offset, callInsn;
482                         struct sigaction  mysigact, oldsigact;
483 #endif
484                         char *ptr;
485                         int foundLib = 0, result;
486                         int done = 0;
487                         elfData = elf_getdata(scn, NULL);
488
489                         ptr = elfData->d_buf;
490                 
491                         map = _r_debug.r_map;
492
493                         while(map && !done){
494                                 if( * map->l_name ){
495                                         diffAddr = checkSOLoadAddr(map->l_name, map->l_addr);
496                                         if(diffAddr){
497                                                 fixInstrumentation(map->l_name, map->l_addr, diffAddr);
498                                         }
499 #if defined(i386_unknown_linux2_0)
500                                         if(strstr(map->l_name, "ld-linux.so")){
501                                                 ld_linuxBaseAddr =map->l_addr;
502                                         }       
503 #endif
504                                 }
505                                 /* check every loaded SO but leave map such that map->l_next == NULL.
506                                         The next time a SO is loaded it will be placed at 
507                                         map->l_next, so keep a tail pointer such that we 
508                                         dont need to loop through the entire list again
509                                 */
510                                 if(map->l_next){
511                                         map = map->l_next;
512                                 }else{
513                                         done = 1;
514                                 }
515                         }
516                         if( shdr->sh_addr == 0){
517                                 /* if the addr is zero, then there is 
518                                         no PLT entry for dlopen.  if there is
519                                         no entry for dlopen the mutatee must not
520                                         call it.  -- what about calling it from
521                                         a shared lib that is statically loaded?
522                                 */
523                                 break;
524                         }
525
526                         /* WHY IS THERE A POUND DEFINE HERE? 
527                                 
528                                 well, we need to intercept the dlopen calls from the mutated binary
529                                 because our trampolines expect the shared libraries to be in
530                                 a particular location and if they are not where they are expected
531                                 our trampolines can jump off into nothingness, or even worse, some
532                                 random bit of executable code.  
533
534                                 So we must intercept the dlopen call and then check to be sure
535                                 the shared libraries are loaded in the same place as before.  If
536                                 they are not we exit with a message to the user saying this is
537                                 a fatal error.
538                 
539                                 Note, only shared libraries that have been instrumented are checked
540                                 here.  
541                         */
542
543 #if defined(sparc_sun_solaris2_4)
544                         /* 
545                                 For a description of what is going on here read
546                                 the comment in dyninst_jump_template above.
547
548                                 This code generated all the instructions refered
549                                 to in that comment as "GENERATED BELOW".
550
551                         */
552                         pltEntry = (unsigned int*) shdr->sh_addr;
553                         pltInsn = *pltEntry; /* save insn for later */
554                         pltEntry += 1;
555                         offset = (*pltEntry) & BA_MASK;
556                         if(offset & 0x00200000){
557                                 /* negative so sign extend */
558                                 offset = 0xffc00000 | offset;
559                         }
560                         PLTEntry = pltEntry;
561                         
562                         PLTEntry += (offset*4)/sizeof(PLTEntry); /* move PLTEntry offset*4 bytes!*/
563                         dyninst_jump_templatePtr = (unsigned int*) & __dyninst_jump_template__;
564
565                         baseAddr = ((unsigned int) dyninst_jump_templatePtr)  -
566                                 ( ((unsigned int) dyninst_jump_templatePtr)% getpagesize());
567                         size =  (unsigned int) dyninst_jump_templatePtr  - baseAddr + 80;
568                         result = mprotect(baseAddr , size, PROT_READ|PROT_WRITE|PROT_EXEC);
569
570                         /* build sethi hi(register_o7), %g1 */
571                         *dyninst_jump_templatePtr = 0x03000000;
572                         *dyninst_jump_templatePtr |= ( (((unsigned int ) & register_o7)& 0xffffe000) >> 10);
573
574                         dyninst_jump_templatePtr ++;
575
576                         /* build st %o7, &register_o7 */
577                         *dyninst_jump_templatePtr = 0xde206000;
578                         *dyninst_jump_templatePtr |=  ( ((unsigned int ) & register_o7) & 0x00001fff );
579
580                         dyninst_jump_templatePtr ++;
581
582                         /* build call PLTEntry */
583                         *dyninst_jump_templatePtr = 0x40000000;
584                         *dyninst_jump_templatePtr |= ( ((unsigned int) (PLTEntry)-  ((unsigned int) dyninst_jump_templatePtr)) >>2);
585                         
586                         dyninst_jump_templatePtr ++;
587
588                         /* copy from plt */
589                         *dyninst_jump_templatePtr = pltInsn;
590                         dyninst_jump_templatePtr ++;
591
592
593                         /* advance past call to pseudoSigHandler */
594                         dyninst_jump_templatePtr = (unsigned int) &__dyninst_jump_template__done__ ;
595         
596                         /* build sethi hi(register_o7), %g1 */
597                         *dyninst_jump_templatePtr = 0x03000000;
598                         *dyninst_jump_templatePtr |= ( (((unsigned int ) & register_o7)& 0xffffe000) >> 10);
599
600                         dyninst_jump_templatePtr ++;
601
602                         /* build ld %o7, register_o7 */
603                         *dyninst_jump_templatePtr = 0xde006000;
604                         *dyninst_jump_templatePtr |=  ( ((unsigned int ) & register_o7) & 0x00001fff );
605
606
607                         /* THIS ENABLES THE JUMP */
608                         /* edit plt to jump to __dyninst_jump_template__ */
609                         baseAddr = ((unsigned int) pltEntry)  -
610                                 ( ((unsigned int) pltEntry)% getpagesize());
611                         size =  (unsigned int) pltEntry  - baseAddr + 8;
612                         result = mprotect(baseAddr , size, PROT_READ|PROT_WRITE|PROT_EXEC);
613
614                         /* build sethi hi(&__dyninst_jump_template__), %g1 */
615                         pltEntry --;
616
617                         *pltEntry = 0x03000000;
618                         *pltEntry |= ( (((unsigned int ) &__dyninst_jump_template__) )>> 10);
619                         pltEntry ++;
620         
621                         /* build jmpl %g1, %r0 */       
622                         *pltEntry = 0x81c06000;
623                         *pltEntry |=  ( ((unsigned int ) &__dyninst_jump_template__ ) & 0x00003ff );
624
625 #elif defined(i386_unknown_linux2_0)
626                         /* install jump to catch call to _dl_debug_state */
627                         /* see comment int hack_ld_linux_plt for explainations */
628                         hack_ld_linux_plt(ld_linuxBaseAddr + shdr->sh_addr); 
629 #endif
630                 }
631                 if(!strncmp((char *)strData->d_buf + shdr->sh_name, "dyninstAPIhighmem_",18)){
632                         /*the layout of dyninstAPIhighmem_ is:
633                         pageData
634                         address of update
635                         size of update
636                         ...     
637                         address of update
638                         size of update  
639                         number of updates
640         
641                         we must ONLY overwrite the updates, the other
642                         areas of the page may be important (and different than
643                         the saved data in the file.  we first copy out the
644                         page, the apply the updates to it, and then
645                         write it back.
646                         */
647
648                         int oldPageDataSize;
649                         retVal = 1; /* just to be sure */
650                         elfData = elf_getdata(scn, NULL);
651                         numberUpdates = (unsigned int) ( ((unsigned int*) elfData->d_buf)[
652                                 (elfData->d_size - sizeof(unsigned int))/ sizeof(unsigned int) ]);
653                         oldPageDataSize = shdr->sh_size-((2*numberUpdates+1)*
654                                 sizeof(unsigned int)) ;
655                         oldPageData = (char*) malloc(oldPageDataSize);
656                         /*copy old page data */
657
658                         /* probe memory to see if we own it */
659                         checkAddr = dladdr((void*)shdr->sh_addr, &dlip); 
660
661                         updateSize  = shdr->sh_size-((2*numberUpdates+1)* sizeof(unsigned int));
662                 
663                         if(!checkAddr){ 
664                                 /* we dont own it,mmap it!*/
665
666                                 mmapAddr = shdr->sh_offset;
667                                 mmapAddr =(unsigned int) mmap((void*) shdr->sh_addr,oldPageDataSize,
668                                         PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_PRIVATE,fd,mmapAddr);
669                         }else{
670                                 /*we own it, finish the memcpy */
671                                 mmapAddr = memcpy(oldPageData, (void*) shdr->sh_addr, updateSize);
672
673                         }
674         
675                         dataPtr =(unsigned int*) &(((char*)  elfData->d_buf)[oldPageDataSize]); 
676                         /*apply updates*/
677                         for(i = 0; i< numberUpdates; i++){
678                                 updateAddress = *dataPtr; 
679                                 updateSize = *(++dataPtr);
680
681                                 updateOffset = updateAddress - shdr->sh_addr;
682                                 /*do update*/   
683                                 memcpy(&( oldPageData[updateOffset]),
684                                                 &(((char*)elfData->d_buf)[updateOffset]) , updateSize); 
685                                 dataPtr ++;
686                         } 
687                         if(!checkAddr){
688                                 mmapAddr = shdr->sh_offset ;
689                                 mmapAddr =(unsigned int) mmap((void*) shdr->sh_addr,oldPageDataSize, 
690                                         PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED| MAP_PRIVATE,fd,mmapAddr);
691
692                         }else{
693                                 memcpy((void*) shdr->sh_addr, oldPageData,oldPageDataSize );
694
695                         }
696                 }
697
698         }
699
700
701         elf_end(elf);
702         close(fd);
703
704         if(soError){
705                 exit(2);
706         }
707         return retVal;
708 }
709
710
711 /* with solaris, the mutatee has a jump from
712  * main() to a trampoline that calls DYNINSTinit() the
713  * trampoline resides in the area that was previously
714  * the heap, this trampoline is loaded as part of the
715  * data segment
716  * UPDATE: now the heap tramps are not loaded by the loader
717  * but rather this file so _init is necessary
718  * UPDATE: gcc handles the _init fine, but
719  * cc chokes on it.  There seems to be no compiler
720  * independent way to have my code called correctly
721  * at load time so i have defined _NATIVESO_ in
722  * the sparc Makefile for cc only.  The #pragma
723  * forces the my_init function to be called 
724  * correctly upon load of the library.
725  * Building with gcc is the same as before. 
726  * THIS NEEDS TO BE FIXED 
727  * 
728  * with linux the trampolines are ALL in the big
729  * array at the top of this file and so are not loaded
730  * by the loader as part of the data segment. this
731  * needs to be called to map in everything before
732  * main() jumps to the big array
733  */ 
734
735 #if defined(_NATIVESO_)
736
737 #pragma init (my_init) 
738 void my_init(){
739 #else 
740 void _init(){
741
742 #endif
743
744 /* this buffer is allocated to clear
745    the first page on the heap. This is necessary
746    because loading the heap tramps uses mmap, which
747    is going to eat the heap if the heap begins on 
748    the same page the heap tramps end on (almost certain)
749 */
750         buffer = (char*) malloc(getpagesize());
751         isElfFile =checkElfFile();
752         free(buffer);
753 }