Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / addLibrary.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 /* -*- Mode: C; indent-tabs-mode: true -*- */
33 // Since the author of this file chose to use tabs instead of spaces
34 // for the indentation mode, the above line switches users into tabs
35 // mode with emacs when editing this file.
36 /* $Id: addLibrary.C,v 1.21 2007/06/13 18:50:26 bernat Exp $ */
37
38
39 #if defined(sparc_sun_solaris2_4)
40 #include "addLibrary.h"
41 #include "util.h"
42 #include "debug.h"
43 #define BASEADDR 0x10000
44
45
46 /* 
47  * This class will add a library to an existing Sparc ELF binary
48  * You must pass it an open Elf * (from libelf) pointer and a library
49  * name, and a name for the new file.
50  *
51  * How it works:
52  * Basically the .dynstr section contains all the strings associated
53  * with the dynamic symbol table and dynamic loading functionality (ie shared
54  * libraries).  The .dynamic table contains a list of dynamic linking
55  * information, including a list of pointers in to the .dynstr table
56  * denoting which shared libraries should be loaded at startup.
57  *
58  * First we must add a string to .dynstr.  Since .dynstr is in the
59  * middle of the text segment we cannot expand it as it will shift
60  * all the following instructions to different addresses in memory
61  * causing much chaos.  So we expand it and shift it up as many
62  * bytes as we expand it, so it ends on the same offset within the
63  * file.  There are no instructions above .dynstr so any movement up
64  * there is ok.  The sections above .dynstr are all accessed through
65  * the Program Header Table or .dynamic table and those pointers
66  * can be patched up easily
67  *
68  * Of course the next question is how do you keep from shifting
69  * up past the beginning of the file? Well and ELF file has as its
70  * first 0x34 bytes the Elf Header.  This is a mandatory position.
71  * Followed by that ELF files usually (ie if they are produced by
72  * gcc) have their Program Header Table (usually 0xc0 bytes) then
73  * the actual data follows that.  The Program Header Table can
74  * be anywhere in the file (*).  So we shift it to either the
75  * end of the text segment or the beginning of the data segment and
76  * patch up the entries in the Program Header Table as needed.  
77  * How do we know we can do this? There is always one memory page
78  * between the end of the text segment and the beginnig of the data
79  * segment.  So either there will be a gap of > 0xc0 bytes between
80  * the end of the text segment and the next page boundry or the start
81  * of the data segment and the previous page boundry.  Note that it
82  * is possible but highly unlikely that the Program Header Table is
83  * greater than 0xc0 bytes, though it would need to grow quite large
84  * for this to be a problem.
85  *
86  * Note that all the assumptions except the placement of the
87  * ELF Header are merely convention, not a standard.  But they are 
88  * followed by gcc and the like.
89  *
90  * UPDATE: 17 may 2002
91  * Previously it was assumed there would be a DT_CHECKSUM entry
92  * in the dynamic table.  this is not always the case. some
93  * compilers dont put this entry in.  If it is not present there
94  * is no place to put the link to the dyninstAPI runtime shared
95  * library and everything fails.  
96  *
97  * UPDATE: 25 june 2003
98  * corrected moveDynamic() to move the .dynamic section to the end
99  * of the text segment
100  * corrected fixUpPhdrForDynamic() to reflect the above change and
101  * make the text segment read/write/execute, instead of just read/execute,
102  * because the .dynamic section gets updated by the loader
103  * 
104  * UPDATE: 26 june 2003
105  * Now the TEXTGAP/DATAGAP test determines if there is enough room for
106  * both the PHT and the .dynamic section in the gap.  
107  *
108  * UPDATE: 27 june 2003
109  * There is a gap of 0x10000 (+ some padding for alignment) bytes between
110  * the end of the text segment and the start of the data segment in MEMORY.
111  * In the original ELF file, the OFFSET for the last byte of the last section
112  * in the text segment and the first byte of the first section in the data section 
113  * are different by 0 to 0x10 bytes (alignment padding).  In the NEW ELF file,
114  * the data segment is shifted down IN THE FILE 0x10000 bytes, keeping the 
115  * 0x0FFFF part of the offset the same so it can be loaded correctly to memory
116  * in the specified location.
117  * This means that there is ALWAYS room to put the PHT and .dynamic section
118  * immediately after the text segment.  The notion of the TEXT and DATA gap
119  * is not important!  
120  *
121  * (*) The Program Header Table should be able to be located
122  * anywhere in the file and loaded to any place in memory.
123  * The Linux loader does not seem to like it if the PHT
124  * is loaded anywhere except in the text or data segment.
125  * I have not been able to find any code to support this,
126  * its all experimental evidence
127  */
128 void addLibrary::createNewElf(){
129
130         Elf32_Ehdr *oldEhdr;
131         Elf32_Phdr *oldPhdr;
132         Elf32_Shdr *oldShdr;
133         Elf_Scn *oldScn;
134         Elf_Data *oldData;
135
136         // get Ehdr
137         oldEhdr = elf32_getehdr(oldElf);
138
139         newElfFileEhdr = (Elf32_Ehdr*) new char[oldEhdr->e_ehsize];
140         memcpy(newElfFileEhdr, oldEhdr, oldEhdr->e_ehsize);
141
142         // get Phdr
143         oldPhdr = elf32_getphdr(oldElf);
144         
145         newElfFilePhdr = (Elf32_Phdr*) new char[oldEhdr->e_phentsize * oldEhdr->e_phnum];
146         memcpy(newElfFilePhdr, oldPhdr, oldEhdr->e_phentsize * oldEhdr->e_phnum);
147
148         newElfFileSec = (Elf_element *) new char[sizeof(Elf_element) * (oldEhdr->e_shnum + 1)];
149         memset(newElfFileSec, '\0',sizeof(Elf_element) * (oldEhdr->e_shnum + 1)); 
150         arraySize = oldEhdr->e_shnum;
151
152         oldScn = NULL;
153         _pageSize = newElfFilePhdr[3].p_align;
154         phdrSize = oldEhdr->e_phentsize * oldEhdr->e_phnum;
155         numberExtraSegs=0;
156         for(int cnt = 0; (oldScn = elf_nextscn(oldElf, oldScn));cnt++){
157                 oldData=elf_getdata(oldScn,NULL);
158                 oldShdr = elf32_getshdr(oldScn);
159
160                 newElfFileSec[cnt].sec_hdr = new Elf32_Shdr;
161                 newElfFileSec[cnt].sec_data = new Elf_Data;
162
163                 memcpy(newElfFileSec[cnt].sec_hdr, oldShdr, sizeof(Elf32_Shdr));
164                 memcpy(newElfFileSec[cnt].sec_data,oldData, sizeof(Elf_Data));
165
166                 if(oldData->d_buf && oldData->d_size){
167                         newElfFileSec[cnt].sec_data->d_buf = new char[oldData->d_size];
168                         memcpy(newElfFileSec[cnt].sec_data->d_buf, oldData->d_buf, oldData->d_size);
169                 }
170                 if(cnt + 1 == newElfFileEhdr->e_shstrndx) {
171                         strTabData = newElfFileSec[cnt].sec_data;
172                 }
173         }
174
175 }
176
177 void addLibrary::updateDynamic(Elf_Data *newData, unsigned int hashOff, unsigned int dynsymOff,
178         unsigned int dynstrOff){
179
180         char *d_buf = new char[newData->d_size +sizeof(Elf32_Dyn) ];
181
182         memset(d_buf, '\0', newData->d_size +sizeof(Elf32_Dyn) ); // make them all DT_NULL
183         memcpy(d_buf, newData->d_buf, newData->d_size );
184         /*fprintf(stderr," NEW DYNAMIC ALLOC %x\n", newData->d_size +sizeof(Elf32_Dyn));*/
185
186         delete [] (char*)newData->d_buf;
187         newData->d_buf = d_buf;
188         newData->d_size += sizeof(Elf32_Dyn);
189         
190         for(unsigned int counter=0;counter<newData->d_size/sizeof(Elf32_Dyn);counter++){
191
192                 if(     ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_HASH ){
193                          ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = hashOff;
194                 }
195                 if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_SYMTAB ){
196                          ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = dynsymOff;
197                 }
198                 if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_STRTAB ) {
199                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = dynstrOff;
200                 }
201
202                 if(     ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_STRSZ ){
203                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val += libnameLen;
204                 }
205 /*
206                 if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_DEBUG){
207                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = 1;
208
209                 }
210 */
211                 if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_NULL) { /* was DT_CHECKSUM */
212                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag = DT_NEEDED;
213                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = libnameIndx;
214                         counter = newData->d_size/sizeof(Elf32_Dyn)+ 1;
215                 }
216         }
217
218 }
219
220 int addLibrary::findSection(const char* name){
221         
222         for(int cnt = 0 ; cnt < arraySize; cnt ++ ){
223                 if (newElfFileSec[cnt].sec_hdr && 
224                         !strcmp(name, (char *)strTabData->d_buf+newElfFileSec[cnt].sec_hdr->sh_name) ) {
225                         return cnt;
226                 }
227         }
228         return -1;
229 }
230
231
232 void addLibrary::updateProgramHeaders(Elf32_Phdr *phdr, unsigned int dynstrOffset){
233
234
235         //update PT_PHDR
236         phdr[0].p_offset = newPhdrOffset;
237         phdr[0].p_vaddr =  newPhdrAddr ;
238         phdr[0].p_paddr = phdr[0].p_vaddr;
239
240         //ccw 27 jun 2003 ALWAYS PUT THE PHT AND .dynamic section IN THE TEXT SEGMENT
241         //update TEXT SEGMENT
242
243         //the PHT is put AFTER the .dynamic section. The phdr slot [0] for the PHT is
244         //already correct.  the new size of the text segment is the distance from
245         //the start of the text segment to the start of the PHT plus the size of the
246         //PHT.  This accounts for the .dynamic section and all padding.
247         phdr[2].p_filesz = ((phdr[0].p_offset - phdr[2].p_offset) + phdr[0].p_filesz);
248         phdr[2].p_memsz = phdr[2].p_filesz;
249
250         /*      i need to make the text section writeable b/c the 
251                 dynamic section is now there and needs
252                 to be updated during execution
253         */      
254         
255         phdr[2].p_flags = PF_R+PF_W+PF_X ; //ccw 26 jun 2003
256         phdr[0].p_flags = PF_R+PF_W+PF_X ; //ccw 30 jun 2003
257
258
259         
260
261         for(int i=0;i<newElfFileEhdr->e_phnum;i++){
262                 if(phdr[i].p_offset && phdr[i].p_offset < dynstrOffset){
263                         phdr[i].p_offset -= libnameLen;
264                         if(phdr[i].p_vaddr){
265                                 phdr[i].p_vaddr -= libnameLen;
266                                 phdr[i].p_paddr -= libnameLen;
267                         }
268                 }else if(phdr[i].p_type != PT_PHDR && phdr[i].p_vaddr > newPhdrAddr){
269                         phdr[i].p_offset +=_pageSize;
270                 }
271         }
272
273
274
275 void addLibrary::addStr(Elf_Data *newData,Elf_Data *oldData, 
276                         const char* libname){
277         newData->d_size += libnameLen;
278         
279         delete [] (char*) newData->d_buf;
280         
281         newData->d_buf = new char[newData->d_size];
282         memcpy(newData->d_buf, oldData->d_buf,oldData->d_size); 
283
284         memcpy(&(((char*) newData->d_buf)[newData->d_size-libnameLen]), libname, libnameLen);
285         libnameIndx = newData->d_size-libnameLen;                       
286
287 }
288
289 int addLibrary::writeNewElf(char* filename, const char* libname){
290
291         Elf32_Ehdr *realEhdr;
292         Elf32_Phdr *realPhdr;
293         Elf_Scn *realScn;
294         Elf32_Shdr *realShdr;
295         Elf_Data *realData, *l_strTabData;
296         unsigned int dynstrOffset;
297         bool seenDynamic = false;
298
299
300         int foundDynstr = 0;
301         
302         //open newElf
303         //if the following call is to open() instead of creat()
304         //and dyninst is compiled with gcc 3.0.[2|4] with -O3 
305         //this file is written as all zeros and the permissions are 
306         //odd ( u=--- g=--S o=r--)
307         
308         //if((newFd = open(filename,  O_WRONLY|O_CREAT|O_TRUNC )) ==-1){
309         //S_IRWXU is not defined in gcc < 3.0
310         if((newFd = creat(filename,0x1c0 /*S_IRWXU*/)) == -1) { 
311                 bperr("cannot creat: %s %d\n",filename,errno);
312                 switch(errno){
313                 case EACCES:
314                         bperr("EACCESS \n");
315                         break;
316                 }
317                 return -1;
318         }
319
320         if((newElf = elf_begin(newFd, ELF_C_WRITE, NULL)) == NULL){
321                 bperr(" elf_begin failed for newElf");
322                 return -1;
323         }
324
325         elf_flagelf(newElf,ELF_C_SET, ELF_F_LAYOUT);
326  
327
328         // ehdr
329         realEhdr = elf32_newehdr(newElf);
330         memcpy(realEhdr,newElfFileEhdr , sizeof(Elf32_Ehdr));
331
332         // phdr
333 //      realEhdr->e_phnum += numberExtraSegs;
334         realPhdr = elf32_newphdr(newElf, realEhdr->e_phnum);
335         memset(realPhdr, '\0', realEhdr->e_phnum * realEhdr->e_phentsize);
336         memcpy(realPhdr, newElfFilePhdr, (realEhdr->e_phnum/*-numberExtraSegs*/) * realEhdr->e_phentsize);
337
338         realEhdr ->e_phoff = newPhdrOffset;
339
340         l_strTabData = newElfFileSec[findSection(".shstrtab")].sec_data; 
341         //section data
342         
343         int pastPhdr = 0;
344
345         unsigned int hashOffset, dynsymOffset, dynstrOffsetNEW;
346         unsigned int hashAlign, dynsymAlign, dynstrAlign;
347
348         int symTabIndex, strTabIndex, dynamicIndex, dynsymIndex, dynstrIndex, hashIndex;
349         dynsymIndex = findSection(".dynsym");
350         dynstrIndex = findSection(".dynstr");
351         hashIndex = findSection(".hash");
352
353         if( dynsymIndex == -1 || dynstrIndex == -1 ){
354                 bperr(" Dynamic symbol table missing...cannot save world\n");
355                 return 0;
356         }
357
358         if( hashIndex == -1 ){
359                 bperr(" Hash table not found...cannot save world\n");
360                 return 0;
361         }
362
363         hashOffset = newElfFileSec[hashIndex].sec_hdr->sh_offset;
364         dynsymOffset = newElfFileSec[dynsymIndex].sec_hdr->sh_offset;
365         dynstrOffsetNEW = newElfFileSec[dynstrIndex].sec_hdr->sh_offset;
366         hashAlign =  newElfFileSec[hashIndex].sec_hdr->sh_addralign;
367
368         dynsymAlign =  newElfFileSec[dynsymIndex].sec_hdr->sh_addralign;
369         dynstrAlign =  newElfFileSec[dynstrIndex].sec_hdr->sh_addralign;
370
371         dynstrOffsetNEW -= libnameLen;
372         while(dynstrOffsetNEW % dynstrAlign){
373                 dynstrOffsetNEW --;
374                 dynsymOffset --;
375                 hashOffset --;
376         }
377         dynsymOffset -= libnameLen;
378
379         while(dynsymOffset % dynsymAlign){
380                 dynsymOffset --;
381                 hashOffset --;
382         }
383
384         hashOffset -=libnameLen;        
385         while(hashOffset % hashAlign){
386                 hashOffset--;
387         }
388         //.interp has align of 1
389
390         unsigned int foundExtraSegment=0, extraSegmentPad=0;
391         
392         dynamicIndex = findSection(".dynamic");
393
394         updateSymbols(newElfFileSec[dynsymIndex].sec_data,newElfFileSec[dynstrIndex].sec_data,
395                 newElfFileSec[dynamicIndex].sec_hdr->sh_addr );
396
397         symTabIndex = findSection(".symtab");
398         strTabIndex = findSection(".strtab");
399
400         if(symTabIndex != -1 && strTabIndex!= -1&&dynamicIndex!= -1){
401                 updateSymbols(newElfFileSec[symTabIndex].sec_data,newElfFileSec[strTabIndex].sec_data,
402                 newElfFileSec[dynamicIndex].sec_hdr->sh_addr );
403         }
404
405
406         int currentOffset=0;//ccw 6 mar 2005 
407         bool bssSeen = false; //ccw 6 mar 2005
408         for(int cnt = 0; cnt < newElfFileEhdr->e_shnum-1 ; cnt++){
409                 realScn = elf_newscn(newElf);
410                 realShdr = elf32_getshdr(realScn);
411                 realData = elf_newdata(realScn);
412
413                 // data
414                 memcpy(realShdr,newElfFileSec[cnt].sec_hdr, sizeof(Elf32_Shdr));
415                 memcpy(realData,newElfFileSec[cnt].sec_data, sizeof(Elf_Data));
416
417                 if(newElfFileSec[cnt].sec_data->d_buf && newElfFileSec[cnt].sec_data->d_size){
418                         realData->d_buf = new char[newElfFileSec[cnt].sec_data->d_size];
419                         memcpy(realData->d_buf, newElfFileSec[cnt].sec_data->d_buf, newElfFileSec[cnt].sec_data->d_size);
420                 }
421                 if(currentOffset){
422                         realShdr->sh_offset = currentOffset;
423                 }
424
425                 if(!foundDynstr){
426                         if(!strcmp(".hash", (char *)l_strTabData->d_buf+realShdr->sh_name)){
427                                 realShdr->sh_offset = hashOffset;
428                         }else if(!strcmp(".dynsym", (char *)l_strTabData->d_buf+realShdr->sh_name)){
429                                 realShdr->sh_offset = dynsymOffset;
430                         }else if(!strcmp(".hash", (char *)l_strTabData->d_buf+realShdr->sh_name)){
431                                 realShdr->sh_offset = dynstrOffsetNEW;
432                         }else{ // .interp 
433                                 realShdr->sh_offset -= libnameLen;
434                         }
435                 }
436
437                 if( !strcmp(".dynamic", (char *)l_strTabData->d_buf+realShdr->sh_name) && !seenDynamic) {
438                         seenDynamic = true; 
439                         updateDynamic(realData, hashOffset+BASEADDR, dynsymOffset+BASEADDR, 
440                                 dynstrOffsetNEW+BASEADDR);
441                         realShdr->sh_size += sizeof(Elf32_Dyn);  // i added a shared library
442                         
443
444                 }else if( !strcmp(".dynamic", (char *)l_strTabData->d_buf+realShdr->sh_name) && seenDynamic) {
445                         realShdr->sh_name = 0;
446                         realShdr->sh_type = 1;
447                         realData->d_size = realShdr->sh_size;
448                         memset(realData->d_buf, '\0', realShdr->sh_size);
449                 }
450
451                 if( !strcmp(".dynstr", (char *)l_strTabData->d_buf+realShdr->sh_name) ){
452                         dynstrOffset = realShdr->sh_offset;
453                         addStr(realData,newElfFileSec[cnt].sec_data, libname);
454                         realShdr->sh_size += libnameLen;
455                         foundDynstr = 1;
456                 }
457                 if( !strcmp(".got", (char *)l_strTabData->d_buf+realShdr->sh_name) ){
458                         //the first int in .got needs to contain the address of
459                         //of the .dynamic section
460                         memcpy( (void*)realData->d_buf, (void*)&newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr, 4);
461                 }
462                 if( pastPhdr || realShdr->sh_addr >= newPhdrAddr){
463                         realShdr->sh_offset+=_pageSize;
464                         //extraSegmentPad+=_pageSize; //ccw 20 apr 2006
465                         pastPhdr = 1;
466                 }
467                 if( !strncmp("dyninstAPI",(char *)l_strTabData->d_buf+realShdr->sh_name, 10)){
468                         realShdr->sh_offset = currentOffset;
469
470                         if(strstr((char *)l_strTabData->d_buf+realShdr->sh_name,"dyninstAPIhighmem")){ //ccw 20 apr 2006 was !strstr
471                                 //since this is not loaded by the loader, ie it is mmaped (maybe)
472                                 //by libdyninstAPI_RT.so it only needs aligned on the real pag size
473                                 //realShdr->sh_offset +=extraSegmentPad; //ccw 23 jul 2003
474                                 //fprintf(stderr,"highmem offset: %x\n",realShdr->sh_offset);
475                                 while( (realShdr->sh_offset)%realPageSize ){
476                                         realShdr->sh_offset ++;
477                                         extraSegmentPad++;
478                                 }
479                                 //fprintf(stderr,"NEW highmem offset: %x\n",realShdr->sh_offset);
480                                 foundExtraSegment = 1;
481                         }else if(strcmp("dyninstAPI_mutatedSO", (char *)l_strTabData->d_buf+realShdr->sh_name)  &&
482                                 strcmp("dyninstAPI_data", (char *)l_strTabData->d_buf+realShdr->sh_name) 
483                                 ){
484         
485                                 //realShdr->sh_offset += extraSegmentPad;
486                                 while( (realShdr->sh_addr - realShdr->sh_offset)%0x10000 ){
487                                         realShdr->sh_offset ++;
488                                         extraSegmentPad++;
489                                 }
490                                 foundExtraSegment = 1;
491
492                         } else{
493                                 //realShdr->sh_offset += extraSegmentPad;
494                         }
495                         currentOffset = realShdr->sh_offset + realShdr->sh_size; 
496                         elf_flagscn(realScn,ELF_C_SET,ELF_F_LAYOUT);
497                         elf_flagshdr(realScn,ELF_C_SET,ELF_F_LAYOUT);
498
499                 }else if(foundExtraSegment){
500                         realShdr->sh_offset += extraSegmentPad;
501                 }
502                 if( !strcmp("rtlib_addr", (char *)l_strTabData->d_buf+realShdr->sh_name) ){
503                         bssSeen = true;
504                         currentOffset = realShdr->sh_offset+realShdr->sh_size;
505                 }else if(strncmp("dyninstAPI",(char *)l_strTabData->d_buf+realShdr->sh_name, 10)){
506
507                         /************************************/
508                         if( bssSeen ){
509                                 realShdr->sh_offset = currentOffset;
510                                 /* INSURE FIX CCW */
511                                 /*      changing d_size will cause us to read beyond the buffer data late 
512                                         we should really realloc data to be of size d_size 
513                                 */
514                                 unsigned int origSize = realData->d_size;
515                                 while((realShdr->sh_offset + realShdr->sh_size) % 8 !=0 ){ 
516                                         realShdr->sh_size++;
517                                         realData->d_size ++;    
518                                 }
519                                 /* REALLOC */
520                                 if( realData->d_size > origSize ){
521                                         char *tmpBuf = new char[realData->d_size];
522                                         memcpy(tmpBuf,realData->d_buf,origSize);
523                                         delete [] (char*)realData->d_buf;
524                                         realData->d_buf = tmpBuf;
525                                 }
526                                 /* REALLOC */
527                                 currentOffset = realShdr->sh_offset + realShdr->sh_size;
528                         }
529                         /***********************************/
530
531                 }
532
533         }
534
535         realEhdr ->e_shoff =currentOffset +1 ;//+= _pageSize + extraSegmentPad; //ccw 20 apr 2006
536         if( realEhdr->e_shoff  % 16 !=0 ){ //ccw 10 mar 2005
537                 realEhdr->e_shoff++;
538         }
539         elf_update(newElf, ELF_C_NULL);
540
541         updateProgramHeaders(realPhdr, dynstrOffset);
542         
543         elf_update(newElf, ELF_C_WRITE);
544         return 1;
545 }
546
547 //if we cannot edit the file (no space at the top, no space
548 //in the text/data gap etc) we return 0.
549 //otherwise we return 1 or 2, depending on if we use the
550 //text gap (1) or the data gap (2)
551 //
552 //If we cannot open the new file we return -1
553 int addLibrary::driver(Elf *elf,  char* newfilename, const char *libname) {
554
555         libnameLen = strlen(libname) +1;
556         oldElf = elf;   
557         //_pageSize = getpagesize();
558         _pageSize = 0x10000;
559         realPageSize = getpagesize();
560         
561         createNewElf();
562         elf_end(elf);
563         textSegEndIndx = findEndOfTextSegment();
564         dataSegStartIndx = findStartOfDataSegment();
565         
566         int gapFlag = checkFile();
567         if(gapFlag){  
568                 
569         
570                 moveDynamic();
571                 findNewPhdrAddr();
572                 findNewPhdrOffset();
573
574                 gapFlag = writeNewElf(newfilename, libname);
575         }else{
576                 //error
577         }
578         return gapFlag;
579 }
580
581
582 void addLibrary::fixUpPhdrForDynamic(){
583
584         //change data segment
585         //change dynamic ptr
586         unsigned int dataSegSizeChange;
587         int dataSegIndex=0, dynSegIndex=0;
588
589         while( newElfFilePhdr[dataSegIndex].p_offset != newElfFileSec[dataSegStartIndx+1].sec_hdr->sh_offset){
590
591                 dataSegIndex++; 
592         }
593                 
594         dataSegSizeChange = newElfFileSec[dataSegStartIndx+1].sec_hdr->sh_offset - 
595                         newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset;
596
597         while( newElfFilePhdr[dynSegIndex].p_type != PT_DYNAMIC){
598                 dynSegIndex ++;
599         }
600         newElfFilePhdr[dynSegIndex].p_offset = newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset;
601         newElfFilePhdr[dynSegIndex].p_vaddr =  newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr;
602         newElfFilePhdr[dynSegIndex].p_filesz += sizeof(Elf32_Dyn);
603         
604
605 }
606
607
608 void addLibrary::moveDynamic(){
609
610         int oldDynamicIndex;
611         int newDynamicIndex;
612         Elf_element *updatedElfFile;
613         Elf32_Shdr tmpShdr;
614
615         oldDynamicIndex = findSection(".dynamic");
616
617         newDynamicIndex = dataSegStartIndx;
618
619         updatedElfFile = (Elf_element*) new char[sizeof(Elf_element) * (newElfFileEhdr->e_shnum+1)]; 
620         memset(updatedElfFile,'\0',sizeof(Elf_element) * (newElfFileEhdr->e_shnum+1));
621         arraySize ++;
622                 
623         for(int cnt = 0, newIndex = 0; cnt < newElfFileEhdr->e_shnum-1 ; cnt++, newIndex++){
624         
625                 if( cnt == newDynamicIndex ){
626                         //copy in dynamic here
627
628                         //save original info for later.
629                         memcpy( &tmpShdr, newElfFileSec[oldDynamicIndex].sec_hdr, sizeof(Elf32_Shdr));
630
631                         memcpy( &(updatedElfFile[newIndex]), &(newElfFileSec[oldDynamicIndex]), sizeof(Elf_element));
632
633                         //ok, now the .dynamic section is at the offset for .got (or whatever is the first in the
634                         //segment
635                         updatedElfFile[newIndex].sec_hdr->sh_offset = newElfFileSec[cnt].sec_hdr->sh_offset; //ccw 27 jun 2003 - 
636                                 //updatedElfFile[newIndex].sec_hdr->sh_size - sizeof(Elf32_Dyn); /* increase in size */
637
638                         while(updatedElfFile[newIndex].sec_hdr->sh_offset  % 0x10){
639                                  updatedElfFile[newIndex].sec_hdr->sh_offset ++; //ccw 27 jun 2003 was: --
640                         }
641
642                         // ccw 25 jun 2003
643                         //ok, we need to find the address of the dynamic section.
644                         //we know the offset in the file.  Given that offset, the address should
645                         //be that offset plus the 'memory offset'.  the 'memory offset' is the difference
646                         //between the real mem location and the file offset.  we calcuate this by using
647                         //the previous (if the dynamic section is at the end of the text segment; if the dynamic section
648                         //is at the start of the data section we use the next) section's information (on the assumption that 
649                         //the previous (next) section and the .dynamic section are in the same segment).
650
651                         updatedElfFile[newIndex].sec_hdr->sh_addr = updatedElfFile[newIndex].sec_hdr->sh_offset +
652                         ( updatedElfFile[newIndex-1].sec_hdr->sh_addr -updatedElfFile[newIndex-1].sec_hdr->sh_offset);
653
654                         // new data!
655                         //updatedElfFile[newIndex].sec_data->d_buf = new char[updatedElfFile[newIndex].sec_data->d_size];
656                         //memcpy(updatedElfFile[newIndex].sec_data->d_buf,newElfFileSec[oldDynamicIndex].sec_data->d_buf,newElfFileSec[oldDynamicIndex].sec_data->d_size);
657                         //fprintf(stderr," NEW ALLOC: %x\n", updatedElfFile[newIndex].sec_data->d_size);
658                          
659
660                         newIndex++;
661                         //copy old entry to to next slot
662                 } 
663                 memcpy( &(updatedElfFile[newIndex]), &(newElfFileSec[cnt]), sizeof(Elf_element));
664                 if(cnt == oldDynamicIndex){
665                         //reset name to zero
666                         //allocat new secHdr
667                         updatedElfFile[newIndex].sec_hdr = new Elf32_Shdr;//(Elf32_Shdr*) new char[sizeof(Elf32_Shdr)];
668
669                         memcpy( updatedElfFile[newIndex].sec_hdr, &tmpShdr, sizeof(Elf32_Shdr));
670                         //updatedElfFile[newIndex].sec_hdr->sh_addr = updatedElfFile[newDynamicIndex].sec_hdr->sh_addr; //ccw 1 jul 2003
671                         
672                 }       
673
674                 if(updatedElfFile[newIndex].sec_hdr->sh_link >= (unsigned int) newDynamicIndex){
675                         updatedElfFile[newIndex].sec_hdr->sh_link++;
676                 }
677                 if(updatedElfFile[newIndex].sec_hdr->sh_info >=  (unsigned int) newDynamicIndex){
678                         updatedElfFile[newIndex].sec_hdr->sh_info++;
679                 }
680
681         }
682
683         newElfFileEhdr->e_shnum++;
684         if(newElfFileEhdr->e_shstrndx >= newDynamicIndex){
685                 newElfFileEhdr->e_shstrndx++;
686         }
687         delete [] newElfFileSec;
688         newElfFileSec = updatedElfFile;
689
690         fixUpPhdrForDynamic();
691 }
692
693 addLibrary::addLibrary(){
694
695         newElfFileSec = NULL;
696         newElfFileEhdr = NULL;
697         newElfFilePhdr = NULL;
698 }
699
700 addLibrary::~addLibrary(){
701         if(newElfFileSec != NULL){
702                 
703                 for(int cnt = 0; cnt < newElfFileEhdr->e_shnum-1 ; cnt++){
704                         delete /*[]*/ newElfFileSec[cnt].sec_hdr; //INSURE
705                         if( cnt != dataSegStartIndx ){ //this is .dynamic, dont delete twice.
706                                 if( newElfFileSec[cnt].sec_data->d_buf ){
707                                         //fprintf(stderr,"deleting: %x %x\n", (unsigned int)newElfFileSec[cnt].sec_data->d_buf,sizeof(newElfFileSec[cnt].sec_data->d_buf));
708                                 
709                                         delete [] (char*) newElfFileSec[cnt].sec_data->d_buf ;
710                                 }
711                         
712                                 delete /*[]*/  newElfFileSec[cnt].sec_data; //INSURE
713                         }
714                 }
715
716                 if(newElfFileEhdr){
717                         delete [] newElfFileEhdr;
718                 }
719                 if(newElfFilePhdr){
720                         delete [] (char*) newElfFilePhdr;
721                 }
722
723                 delete [] newElfFileSec;
724         }
725         elf_end(newElf);
726         P_close(newFd);
727
728 }
729
730 unsigned int addLibrary::findEndOfTextSegment(){
731 //newElfFilePhdr
732         Elf32_Phdr *tmpPhdr = newElfFilePhdr;
733         unsigned int lastOffset;
734         unsigned int retVal=0;
735
736         while(tmpPhdr->p_type != PT_LOAD){      
737                 //find first loadable segment
738                 //it should be the text segment
739                 tmpPhdr++;
740         }
741         lastOffset = tmpPhdr->p_offset + tmpPhdr->p_filesz;
742
743         for(int i=0;i<arraySize && !retVal; i++){
744
745                 if( lastOffset == newElfFileSec[i].sec_hdr->sh_offset + newElfFileSec[i].sec_hdr->sh_size){
746                         //found it!
747                         retVal = i;
748                 }
749         }
750         
751
752         return retVal;
753         
754         
755 }
756
757 unsigned int addLibrary::findStartOfDataSegment(){
758         Elf32_Phdr *tmpPhdr = newElfFilePhdr;
759         unsigned int firstOffset;
760         unsigned int retVal=0;
761
762         while(tmpPhdr->p_type != PT_LOAD){      
763                 //find first loadable segment
764                 //it should be the text segment
765                 tmpPhdr++;
766         }
767         tmpPhdr++;
768         while(tmpPhdr->p_type != PT_LOAD){      
769                 //find second loadable segment
770                 //it should be the data segment
771                 tmpPhdr++;
772         }
773
774         firstOffset = tmpPhdr->p_offset;
775
776         for(int i=0;i<arraySize && !retVal; i++){
777
778                 if( firstOffset == newElfFileSec[i].sec_hdr->sh_offset){
779                         //found it!
780                         retVal = i;
781                 }
782         }
783         return retVal;
784 }
785
786
787 int addLibrary::findNewPhdrAddr(){
788         //ccw 27 jun 2003 THIS MUST BE CALLED AFTER moveDynamic() !!
789         //and before writeElf
790         Elf32_Shdr *tmpShdr;
791
792
793         tmpShdr = newElfFileSec[findSection(".dynamic")].sec_hdr;
794         //i have not yet added the extra record the .dynamic table so account for that 
795         //in the addr calc!
796         newPhdrAddr = tmpShdr->sh_addr + tmpShdr->sh_size + sizeof(Elf32_Dyn);
797         
798         while(newPhdrAddr %4){
799                 newPhdrAddr ++;
800         }       
801
802         return 0;               
803 }
804
805 int addLibrary::findNewPhdrOffset(){
806         Elf32_Shdr *tmpShdr;
807         //ccw 27 jun 2003 THIS MUST BE CALLED AFTER moveDynamic() !!
808         //and before writeElf
809         
810         tmpShdr = newElfFileSec[findSection(".dynamic")].sec_hdr;
811         //i have not yet added the extra record the .dynamic table so account for that 
812         //in the offset calc!
813         newPhdrOffset = tmpShdr->sh_offset + tmpShdr->sh_size + sizeof(Elf32_Dyn);
814
815         while(newPhdrOffset %4){
816                 newPhdrOffset ++;
817         }       
818
819
820         return 0;       
821 }
822
823
824 int addLibrary::checkFile(){
825         Elf32_Shdr *roDataShdr, *dataShdr;
826         unsigned int endrodata, startdata;
827         char extraSegName[20];
828         
829         //is there space at the beginning?
830         
831         //must be space between 0x34 (end of the ehdr) and
832         //the text segment start.
833         
834         if(newElfFileSec[0].sec_hdr->sh_offset < (unsigned int) (sizeof(Elf32_Ehdr)+libnameLen) ){
835                 //there is not enough room
836                 return 0;
837         }
838
839         roDataShdr = newElfFileSec[/*findSection(".rodata")*/ textSegEndIndx].sec_hdr;
840         dataShdr = newElfFileSec[/*findSection(".data")*/ dataSegStartIndx].sec_hdr;
841
842         numberExtraSegs = 0;
843         sprintf(extraSegName,"dyninstAPI_%08x", numberExtraSegs);
844
845         while ( findSection(extraSegName) != -1 ){
846                 numberExtraSegs ++;
847                 sprintf(extraSegName,"dyninstAPI_%08x", numberExtraSegs);
848         }       
849
850         endrodata = roDataShdr->sh_addr + roDataShdr->sh_size;
851
852         startdata = dataShdr -> sh_addr;
853
854         return 1;//result; //ccw 27 jun 2003
855
856 }
857
858 //This method updates the symbol table,
859 //it updates the address of _DYNAMIC
860 void addLibrary::updateSymbols(Elf_Data* symtabData,Elf_Data* strData, unsigned int dynAddr){
861
862         if( symtabData && strData){
863         
864                 Elf32_Sym *symPtr=(Elf32_Sym*)symtabData->d_buf;
865
866                 for(unsigned int i=0;i< symtabData->d_size/(sizeof(Elf32_Sym));i++,symPtr++){
867
868         
869                         if( !(strcmp("_DYNAMIC", (char*) strData->d_buf + symPtr->st_name))){
870                                 symPtr->st_value = dynAddr;
871                         }
872                 }
873         }
874 }
875
876
877 #endif