Sets the brk pointer for save-the-world binaries to what it was when each
[dyninst.git] / dyninstAPI_RT / src / RTmutatedBinary_XCOFF.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_XCOFF.c,v 1.10 2006/01/13 00:00:48 jodom Exp $ */
43
44
45 /* this file contains the code to restore the necessary
46    data for a mutated binary in XCOFF format
47  */
48
49
50 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include  <fcntl.h>
55 #include <errno.h>
56 #include <sys/mman.h>
57 #include <dlfcn.h>
58 #include <limits.h>
59 #include <sys/stat.h>
60 #include <xcoff.h>
61
62 /* Copied from RTheap-aix.c */
63 extern Address DYNINSTheap_loAddr;
64 extern Address DYNINSTheap_hiAddr;
65
66
67 unsigned int checkAddr;
68 /*char *buffer;
69 extern int isMutatedExec;
70 */
71
72
73 /*      this is not misnamed.  In the future, this function will contain
74         code to patch the instrumentation of a shared library that has 
75         been loaded into a different place during a mutated binary run.
76
77         Now, it just exit()s, as you can see
78 */
79
80 void fixInstrumentation(char* soName, unsigned int currAddr, unsigned int oldAddr){
81         printf(" %s loaded at wrong address: 0x%x (expected at 0x%x) \n", soName, currAddr, oldAddr);
82         printf(" This is an unrecoverable error, the instrumentation will not");
83         printf("\n run correctly if shared libraries are loaded at a different address\n");
84         printf("\n Exiting.....\n");
85         fflush(stdout);
86         exit(9);
87 }
88
89 void* loadFile(char *name, int *fd){
90
91         struct stat statInfo;
92         int statRet ;
93
94         *fd = open( name, O_RDONLY);
95
96         if( *fd == -1 ){
97                 /*printf("cannot open : %s\n",name);
98                 fflush(stdout); */
99                 return 0;
100         }
101
102
103         statRet = fstat(*fd, &statInfo);        
104         
105         if( statRet == -1) {
106                 printf(" no stats found for %s \n",name);
107                 close(*fd);
108                 return 0;
109         }
110         
111         return mmap(0x0, statInfo.st_size, PROT_READ, MAP_FILE, *fd,0x0); 
112
113 }
114
115 int checkMutatedFile(){
116
117
118         int       cnt,fd;
119         char execStr[256];
120         int retVal = 0, result;
121         unsigned int mmapAddr;
122         int pageSize;
123         Address dataAddress;
124         int dataSize;
125         char* tmpPtr;
126         unsigned int updateAddress, updateSize, updateOffset;
127         unsigned int *dataPtr;
128         unsigned int numberUpdates,i ;
129         char* oldPageData;
130         int sawFirstHeapTrampSection = 0;
131
132         struct scnhdr *currScnhdr, *firstScnhdr;
133         struct xcoffhdr *XCOFFhdr;
134         char *data;
135         void *XCOFFfile;
136         unsigned int *numbNewHdrs;
137         snprintf(execStr,255,"%s/dyninst_mutatedBinary",getenv("PWD"));
138
139
140         XCOFFfile = loadFile(execStr, &fd);
141
142         if(!XCOFFfile){
143                 /*printf("Cannot restore mutated binary\n\n");*/
144                 return 0;
145         }
146
147         /*fprintf(stderr," restoring mutated binary...");*/
148
149         XCOFFhdr = (struct xcoffhdr*) XCOFFfile;
150
151
152         /*      WHAT IS GOING ON HERE?
153                 I cannot put the extra data (tramps, highmem data, shared lib info)
154                 in the middle of the file as in the ELF stuff.  I must place it at
155                 the end, AFTER the symbol table and string table.  Really this is
156                 like having two XCOFF files stuck together.  THe loader only pays
157                 attention to the first one (ie the one refered to by the file header
158                 info).  The stuff tacked on at the end is as follows:
159
160                 number of sections
161                 section header
162                 section header
163                 ...
164                 section data
165                 section data
166                 ...
167
168                 I need to find the end of the string table and then pull out the
169                 number of section headers tacked on to the end.  Then I can
170                 go through the section data a section at a time.
171                 
172         */
173
174         /*fine end of symbol table*/
175         firstScnhdr = (struct scnhdr*) ( ((char*) XCOFFfile) + XCOFFhdr->filehdr.f_symptr +
176                         XCOFFhdr->filehdr.f_nsyms * 18); /* 18 == sizeof symbol */
177         /*find end of string table*/
178         numbNewHdrs = (unsigned int*) ( ((char*) firstScnhdr ) + *((unsigned int*) firstScnhdr));
179                 /*(struct scnhdr*)  ( (char*) XCOFFfile + sizeof(struct xcoffhdr));*/
180
181         firstScnhdr = (struct scnhdr *) ( sizeof(unsigned int) + ((char*) firstScnhdr ) + *((unsigned int*) firstScnhdr));
182
183         currScnhdr = firstScnhdr;
184
185         pageSize =  getpagesize();
186
187         for(currScnhdr = firstScnhdr, cnt=0; cnt < *numbNewHdrs; currScnhdr++, cnt++){
188                 if(!strcmp( currScnhdr->s_name, "dyn_lib")){
189                         /* use dlopen to load a list of shared libraries */
190
191                         int len;
192                         void *old_brk, *new_brk;
193
194                         data = (char*) XCOFFfile + currScnhdr->s_scnptr;
195                         memcpy( &new_brk, data + strlen(data) + 1, sizeof(void *));
196                         while(*data != '\0'){
197                            if ((old_brk = sbrk(0)) > new_brk) {
198                               printf("current BRK 0x%p > desired BRK 0x%p for %s!\n",
199                                      old_brk,
200                                      new_brk,
201                                      data);
202                               fflush(stdout);
203                            } else {
204                               brk(new_brk);
205                            }
206                                 DYNINSTloadLibrary(data);
207                                 data += (strlen(data) +1 + sizeof(void *));
208                         }
209                 }else if(!strcmp( currScnhdr->s_name, "dyn_dat")){
210                         /* reload data */
211                         tmpPtr =  (char*) XCOFFfile + currScnhdr->s_scnptr;
212                         dataAddress = -1;
213                         while( dataAddress != 0 ) { 
214                                 dataSize = *(int*) tmpPtr;
215                                 tmpPtr+=sizeof(int);
216                                 dataAddress = *(Address*) tmpPtr;
217                                 tmpPtr += sizeof(Address);
218                                 if(dataAddress){
219                                         memcpy((char*) dataAddress, tmpPtr, dataSize);
220                                         tmpPtr += dataSize;
221                                 }
222                         }
223                         retVal = 1;
224
225                 }else if(!strncmp( currScnhdr->s_name, "dyn_",4)){
226
227                         /* THIS SHOULD NEVER OCCUR!*/
228
229                         /* heap tramps */
230                         char *tmpStr;
231                         printf("%s\n",  currScnhdr->s_name);
232                         retVal = 1; /* this is a restored run */
233
234                         tmpStr = &currScnhdr->s_name[4]; 
235                         if( *tmpStr>=0x30 && *tmpStr <= 0x39 ) {
236                                 /* this is a heap tramp section */
237                                 if( sawFirstHeapTrampSection ){
238
239                                         result = (int)mmap((void*) currScnhdr->s_vaddr, currScnhdr->s_size, 
240                                         PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS| MAP_FIXED,-1,0);
241                                         if( result == -1){
242
243                                                 mprotect((void*) currScnhdr->s_vaddr, currScnhdr->s_size,
244                                                         PROT_READ|PROT_WRITE|PROT_EXEC);
245                                                 result = (int) mmap((void*) currScnhdr->s_vaddr, currScnhdr->s_size, 
246                                                 PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS| MAP_FIXED,-1,0);
247                                                 if( result == -1){
248                                                 perror("TRYING TO MMAP:");
249                                                 switch(errno){
250                                                         case EACCES:
251                                                                 printf(" EACCES \n");
252                                                                 break;
253                                                         case EBADF:
254                                                                 printf(" EBADF \n");
255                                                                 break;
256                                                         case EINVAL:
257                                                                 printf(" EINVAL\n");
258                                                                 break;
259                                                         case ENOMEM:
260                                                                 printf(" NO MEM!\n");
261                                                                 break;
262                                                         default:
263                                                                 printf(" OTHER ERROR %d\n",errno);
264                                                 }
265                                                 }
266                                         }
267
268                                         printf(" MMAP! vaddr %x size %x scnptr %x : result %x",currScnhdr->s_vaddr,currScnhdr->s_size,currScnhdr->s_scnptr, result );
269                                         fflush(stdout);
270
271                                         memcpy((void *) currScnhdr->s_vaddr, ((char*) XCOFFfile) + currScnhdr->s_scnptr,
272                                                 currScnhdr->s_size);
273 /*                                      result = mmap((void*) currScnhdr->s_vaddr, currScnhdr->s_size, 
274                                         PROT_READ|PROT_WRITE|PROT_EXEC,
275                                         MAP_FIXED|MAP_PRIVATE,fd,currScnhdr->s_scnptr);
276                                         printf(" RESULT! %x", result);*/
277                                 }else{
278
279                                         printf(" mmecpy! %x %x %x",currScnhdr->s_vaddr,currScnhdr->s_size,
280                                                 ((char*) XCOFFfile) + currScnhdr->s_scnptr );
281                                         fflush(stdout);
282
283                                         /*memcpy(currScnhdr->s_vaddr, ((char*) XCOFFfile) + currScnhdr->s_scnptr, currScnhdr->s_size);*/
284                                         sawFirstHeapTrampSection = 1;
285                                 }
286                         }
287
288                 }else if(!strncmp( currScnhdr->s_name, "dyH_", 4)){
289                         /* high mem tramps */
290
291                         /*the layout of dyninstAPIhighmem_ is:
292                         pageData
293                         address of update
294                         size of update
295                         ...     
296                         address of update
297                         size of update  
298                         number of updates
299         
300                         we must ONLY overwrite the updates, the other
301                         areas of the page may be important (and different than
302                         the saved data in the file.  we first copy out the
303                         page, the apply the updates to it, and then
304                         write it back.
305                         */
306
307                         int oldPageDataSize;
308                         int dataSize = currScnhdr->s_size;
309                         /*Dl_info dlip;*/
310
311                         retVal = 1; /* just to be sure */
312
313                         data = (char*) XCOFFfile + currScnhdr->s_scnptr ;
314                         
315                         numberUpdates = (unsigned int) ( ((unsigned int*) data)[
316                                 (dataSize - sizeof(unsigned int))/ sizeof(unsigned int) ]);
317                         oldPageDataSize = dataSize-((2*numberUpdates+1)*
318                                 sizeof(unsigned int)) ;
319                         oldPageData = (char*) malloc(oldPageDataSize);
320                         /*copy old page data */
321
322                         /* probe memory to see if we own it */
323                         checkAddr = 1;/*dladdr((void*)currScnhdr->s_vaddr, &dlip); */
324
325                         updateSize  = dataSize-((2*numberUpdates+1)* sizeof(unsigned int));
326
327             /* Actually have a checkAddr... */
328             if (currScnhdr->s_vaddr >= DYNINSTheap_loAddr &&
329                 currScnhdr->s_vaddr <= DYNINSTheap_hiAddr)
330                 checkAddr = 0;
331             
332                         if(!checkAddr){ 
333                                 /* we dont own it,mmap it!*/
334                 int fdzero = open("/dev/zero", O_RDWR);
335                 mmapAddr = 0;
336                 mmapAddr =(unsigned int) mmap((void*) currScnhdr->s_vaddr,
337                                               oldPageDataSize,
338                                               PROT_READ|PROT_WRITE|PROT_EXEC,
339                                               MAP_FIXED|MAP_PRIVATE,
340                                               fdzero,
341                                               0);
342                 close(fdzero);
343                                 mmapAddr = (unsigned int) memcpy(oldPageData,
344                                   (void*)currScnhdr->s_vaddr ,
345                                   updateSize);
346                 checkAddr = 1;
347                         }else{
348                                 /*we own it, finish the memcpy */
349                                 mmapAddr = (unsigned int) memcpy(oldPageData, (void*)currScnhdr->s_vaddr , updateSize);
350                                 checkAddr = 1; 
351                         }
352         
353                         dataPtr =(unsigned int*) &(data[oldPageDataSize]);      
354                         /*apply updates*/
355                         for(i = 0; i< numberUpdates; i++){
356                                 updateAddress = *dataPtr; 
357                                 updateSize = *(++dataPtr);
358
359                                 updateOffset = updateAddress -  currScnhdr->s_vaddr;
360                                 /*do update*/   
361                                 memcpy(&( oldPageData[updateOffset]),
362                                                 &(data[updateOffset]) , updateSize);    
363                                 dataPtr ++;
364                         } 
365                         if(!checkAddr){
366                                 mmapAddr =  currScnhdr->s_scnptr;
367                                 mmapAddr =(unsigned int) mmap((void*) currScnhdr->s_vaddr,oldPageDataSize, 
368                                         PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED| MAP_PRIVATE,fd,mmapAddr);
369
370                         }else{
371                                 if( currScnhdr->s_vaddr < 0xd0000000){
372                                 /*mmapAddr = currScnhdr->s_vaddr - (currScnhdr->s_vaddr %pageSize);
373
374                                 mmapAddr = mmap(mmapAddr,currScnhdr->s_vaddr - mmapAddr + oldPageDataSize, 
375                                         PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_FIXED |MAP_PRIVATE,-1,0);
376                                 
377                                 perror(" MMAP ");
378                                 printf(" MMAP: %x \n", mmapAddr);
379                                 */
380                                 mmapAddr = currScnhdr->s_vaddr - (currScnhdr->s_vaddr %pageSize);
381
382                                 checkAddr = mprotect((void *)mmapAddr, currScnhdr->s_vaddr - mmapAddr + oldPageDataSize, 
383                                         PROT_READ|PROT_WRITE|PROT_EXEC);
384                                 /*printf(" MPROTECT: %x %lx : %lx \n", checkAddr, mmapAddr,currScnhdr->s_vaddr - mmapAddr + oldPageDataSize
385  );*/
386
387                                 memcpy((void*)currScnhdr->s_vaddr, oldPageData,oldPageDataSize );
388                                 }
389                         }
390                         free(oldPageData);
391                 }
392         }
393
394         fflush(stdout);
395         close(fd);
396
397         return retVal;
398 }
399
400