Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / saveSharedLibrary.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 #include "saveSharedLibrary.h"
33 #include "util.h"
34
35 #if defined(sparc_sun_solaris2_4) \
36  || defined(i386_unknown_linux2_0) \
37  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
38
39 saveSharedLibrary::saveSharedLibrary(sharedLibrary sharedLib, char* newname){
40         soObject.setpathname(sharedLib.getpathname());
41         soObject.setbase_addr(sharedLib.getbase_addr());
42         if(newname){
43                 newpathname = new char[strlen(newname) +1];
44                 strcpy(newpathname, newname);   
45         }else{
46                 newpathname = NULL;
47         }       
48         newShstrtabData_d_buf=NULL;
49 }
50
51 saveSharedLibrary::saveSharedLibrary(Address baseAddr, const char* oldname,
52                         char* newname){
53         soObject.setbase_addr(baseAddr);
54         soObject.setpathname(oldname);
55         newpathname = new char[strlen(newname) +1];
56         strcpy(newpathname, newname);   
57         newShstrtabData_d_buf=NULL;
58 }
59
60 saveSharedLibrary::saveSharedLibrary(): newpathname(NULL),newShstrtabData_d_buf(NULL) {}
61
62 void saveSharedLibrary::getTextInfo(Address &textScnAddr, Address &textScnSize){
63         textScnAddr = textAddr;
64         textScnSize = textSize;
65 }
66
67 void saveSharedLibrary::setnewname(char *newname){
68         if(newpathname){
69                 delete [] newpathname;
70         }
71         newpathname = new char[strlen(newname) +1];
72         strcpy(newpathname, newname);   
73 }
74
75 bool saveSharedLibrary::openElf(){
76            elf_version(EV_CURRENT);
77            /*if((oldfd = open(soObject.getpathname(), O_RDONLY)) == -1){ 
78                          fprintf(stderr,"cannot open Old SO: %s\n",soObject.getpathname());
79                          perror(" FAIL ");
80                          return false;;
81            }
82           if((oldElf = elf_begin(oldfd, ELF_C_READ, NULL)) ==NULL){
83                          fprintf(stderr,"cannot open ELF %s \n", soObject.getpathname());
84                          return false;;
85            }*/
86
87            if((newfd = (open(newpathname, O_RDWR)))==-1){
88                          fprintf(stderr,"%s[%d]: cannot open new SO : %s\n",FILE__, __LINE__,newpathname);
89                          perror(" FAIL ");
90                          return false;;
91            }
92            if((newElf = elf_begin(newfd, ELF_C_RDWR, NULL)) ==NULL){
93                          fprintf(stderr,"cannot open ELF %s \n", newpathname);
94                          return false;;
95            }
96           return readNewLib();
97 }
98
99 saveSharedLibrary::~saveSharedLibrary(){
100         if(newpathname){
101                 delete []newpathname;
102         }
103         if( newShstrtabData_d_buf ){
104                 delete [] newShstrtabData_d_buf;
105         }
106 }
107
108 bool saveSharedLibrary::readNewLib(){
109         Elf32_Shdr *newsh, *shdr;
110         Elf_Scn *scn, *newScn;
111         Elf32_Ehdr *ehdr;
112         Elf32_Phdr *oldPhdr;
113         Elf_Data  *strdata, *newdata, *olddata;
114
115         if ((ehdr = elf32_getehdr(newElf)) == NULL){ 
116                 fprintf(stderr," FAILED obtaining ehdr readNewLib\n");
117                 return false;
118         }
119
120
121         if((scn = elf_getscn(newElf, ehdr->e_shstrndx)) != NULL){
122                 if((strdata = elf_getdata(scn, NULL)) == NULL){
123                         fprintf(stderr," Failed obtaining .shstrtab data buffer \n");
124                         return false;
125                 }
126         }else{
127                 fprintf(stderr," FAILED obtaining .shstrtab scn\n");
128         }
129
130         unsigned int newScnName =0;
131         scn = NULL;
132         Elf_Data shstrtabData;
133 #if  defined(i386_unknown_linux2_0) \
134  || defined(x86_64_unknown_linux2_4) 
135         /* save the PHDR from the library */
136      oldPhdr = elf32_getphdr(newElf);
137         Elf32_Phdr phdrBuffer[ehdr->e_phnum];
138         /*      copy it over to a buffer because, on linux, we will close newElf and reopen it.
139                 This closing of newElf should dealloc the data pointed to by oldPhdr
140         */
141         memcpy(phdrBuffer, oldPhdr, ehdr->e_phnum * ehdr->e_phentsize);
142 #endif
143
144         for (int cnt = 1; (scn = elf_nextscn(newElf, scn)); cnt++) {
145                  //copy sections from newElf to newElf.
146
147                  shdr = elf32_getshdr(scn);
148                  olddata = elf_getdata(scn,NULL);
149
150
151                  if(!strcmp( (char *)strdata->d_buf + shdr->sh_name, ".text")){
152                             textAddr = shdr->sh_addr;
153                                 textData = olddata;
154                                 textSize = shdr->sh_size;
155                  }
156
157                  if(!strcmp( (char*) strdata->d_buf + shdr->sh_name, ".shstrtab")){
158                             const char *secname =".dyninst_mutated\0";
159                             shstrtabData.d_size = olddata->d_size+strlen(secname)+1;
160                                 newShstrtabData_d_buf = new  char[shstrtabData.d_size];
161                             shstrtabData.d_buf = newShstrtabData_d_buf;
162                             memcpy( shstrtabData.d_buf,  olddata->d_buf, olddata->d_size);
163                             memcpy(&(((char*) shstrtabData.d_buf)[olddata->d_size]), secname,
164                                           strlen(secname)+1);
165
166                             newScnName = olddata->d_size;
167                             olddata->d_buf = shstrtabData.d_buf;
168                             olddata->d_size = shstrtabData.d_size;
169
170                             shdr->sh_size +=strlen(secname)+1;
171
172                                 /*      if the section header table is past this section in the
173                                         ELF file, calculate the new offset*/
174                                 if(ehdr ->e_shoff > shdr->sh_offset){
175                                         ehdr->e_shoff += strlen(secname)+1;
176                                 }
177                                 elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY);
178
179                  }
180
181         }
182
183
184
185         ehdr-> e_shnum++;
186         newScn = elf_newscn(newElf);
187
188         newsh = elf32_getshdr(newScn);
189
190         newsh->sh_name = newScnName;
191         newsh->sh_type = SHT_NOBITS; // SHT_NOTE;
192         newsh->sh_flags=0;
193         newsh->sh_addr = 0x0;
194         newsh->sh_offset = shdr->sh_offset;
195         newsh->sh_size=0;
196         newsh->sh_link=0;
197         newsh->sh_info=0;
198         newsh->sh_addralign = 0x1; //Values 0 and 1 mean the section has no alignment constraints.
199         newsh->sh_entsize = 0;
200
201
202         newdata = elf_newdata(newScn);
203         newdata->d_size =0;
204         newdata->d_buf=0;
205
206         elf_update(newElf, ELF_C_NULL);
207
208         /*      elfutils on linux does not write data back to an ELF file you
209                 have opened correctly. Specifically, if you add a section the
210                 section's section header has space allocated for it in the file
211                 but no data is written to it. lovely, eh?
212
213                 to combat this, we reopen the file we just closed, and find the
214                 empty section header and fill it with data.
215         */
216
217 #if  defined(i386_unknown_linux2_0) \
218  || defined(x86_64_unknown_linux2_4) 
219
220         elf_update(newElf, ELF_C_WRITE);
221         elf_end(newElf);
222         P_close(newfd);
223
224         if((newfd = (open(newpathname, O_RDWR)))==-1){
225                 fprintf(stderr,"%s[%d]: cannot open new SO : %s\n",FILE__, __LINE__, newpathname);
226                 perror(" FAIL ");
227                 return false;;
228         }
229         if((newElf = elf_begin(newfd, ELF_C_RDWR, NULL)) ==NULL){
230                 fprintf(stderr,"cannot open ELF %s \n", newpathname);
231                 return false;;
232         }
233         if ((ehdr = elf32_getehdr(newElf)) == NULL){ 
234                 fprintf(stderr," FAILED obtaining ehdr readNewLib\n");
235                 return false;
236         }
237
238
239         if((scn = elf_getscn(newElf, ehdr->e_shstrndx)) != NULL){
240                 if((strdata = elf_getdata(scn, NULL)) == NULL){
241                         fprintf(stderr," Failed obtaining .shstrtab data buffer \n");
242                         return false;
243                 }
244         }else{
245                 fprintf(stderr," FAILED obtaining .shstrtab scn\n");
246         }
247
248         scn = NULL;
249         bool foundText=false; 
250         for (int cnt = 1; (scn = elf_nextscn(newElf, scn)); cnt++) {
251                  //copy sections from newElf to newElf.
252
253                  shdr = elf32_getshdr(scn);
254                  olddata = elf_getdata(scn,NULL);
255
256
257                 if(!foundText && !strcmp( (char *)strdata->d_buf + shdr->sh_name, ".text")){
258                         textAddr = shdr->sh_addr;
259                         textData = olddata;
260                         textSize = shdr->sh_size;
261                         elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY);
262                         foundText = true;
263                 }       
264
265         }
266
267                 /**UPDATE THE LAST SHDR **/
268         memset(shdr,'\0', sizeof(Elf32_Shdr));  
269         shdr->sh_name = newScnName;
270         shdr->sh_addr = 0x0;
271         shdr->sh_type = 7;
272
273         /*      update the PHDR, well just make sure it is reset to 
274                 what was in the original library */
275      Elf32_Phdr *newPhdr = elf32_getphdr(newElf);
276         memcpy(newPhdr,phdrBuffer, ehdr->e_phnum * ehdr->e_phentsize);
277
278         /* be extra sure, set the DIRTY flag */
279         elf_flagphdr(newElf, ELF_C_SET,ELF_F_DIRTY);
280         elf_flagscn(scn,ELF_C_SET,ELF_F_DIRTY);
281         elf_update(newElf, ELF_C_NULL);
282 #endif
283         return true;
284
285 }
286
287 void saveSharedLibrary::closeElf(){
288
289         elf_update(newElf, ELF_C_NULL);
290         elf_update(newElf, ELF_C_WRITE);
291         elf_end(newElf);
292         P_close(newfd);
293 }
294
295 void saveSharedLibrary::closeOriginalLibrary(){
296         /*elf_end(oldElf);
297         P_close(oldfd);*/
298 }
299
300
301 void saveSharedLibrary::openBothLibraries(){
302
303         if(!soObject.getpathname()){
304                 return;
305         }
306         
307         openElf();
308 }
309
310 void saveSharedLibrary::closeNewLibrary(){
311         closeElf();
312 }
313
314 void saveSharedLibrary::saveMutations(char *textInsn){
315
316         memcpy(textData->d_buf, textInsn, textData->d_size);    
317         elf_flagdata(textData,ELF_C_SET,ELF_F_DIRTY);
318
319 }
320
321 /* get the text section from the ORIGINAL library */
322 /*char* saveSharedLibrary::getTextSection(){
323         Elf32_Shdr  *shdr;
324         Elf_Scn *scn; 
325            Elf32_Ehdr *ehdr = elf32_getehdr(oldElf);
326         Elf_Data *strdata,*olddata;
327
328         char * textSection=NULL;
329
330         if (((ehdr = elf32_getehdr(oldElf)) != NULL)){ 
331                 if((scn = elf_getscn(oldElf, ehdr->e_shstrndx)) != NULL){
332                         if((strdata = elf_getdata(scn, NULL)) == NULL){
333                                 fprintf(stderr," Failed obtaining .shstrtab data buffer \n");
334                                 return NULL;
335                         }
336                 }else{
337                         fprintf(stderr," FAILED obtaining .shstrtab scn\n");            
338                         return NULL;
339                 }
340         }else{
341                 fprintf(stderr," FAILED obtaining .shstrtab ehdr\n");
342                 return NULL;
343         }
344
345         scn = NULL;
346         for (int cnt = 1; (scn = elf_nextscn(oldElf, scn)); cnt++) {
347                 //copy sections from oldElf to newElf.
348         
349                 shdr = elf32_getshdr(scn);
350                 olddata = elf_getdata(scn,NULL);
351
352                 if(!strcmp( (char *)strdata->d_buf + shdr->sh_name, ".text")){
353
354                         textSection = new char[olddata->d_size];
355                         memcpy(textSection, olddata->d_buf, olddata->d_size);
356                 }
357         }
358
359         return textSection;
360 }*/
361
362 #endif
363
364 // vim:ts=5: