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