Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / addLibraryLinux.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: addLibraryLinux.C,v 1.22 2008/06/19 19:53:03 legendre Exp $ */
33
34 #if defined(i386_unknown_linux2_0) \
35  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */
36
37 #include "addLibraryLinux.h"
38 #include "util.h"
39 #include "debug.h"
40 #define MOVEDYNAMIC 1 
41
42 /* 
43  * This class will add a library to an existing Linux ELF binary
44  * You must pass it an open Elf * (from libelf) pointer and a library
45  * name, and a name for the new file.
46  *
47  * How it works:
48  * Basically the .dynstr section contains all the strings associated
49  * with the dynamic symbol table and dynamic loading functionality (ie shared
50  * libraries).  The .dynamic table contains a list of dynamic linking
51  * information, including a list of pointers in to the .dynstr table
52  * denoting which shared libraries should be loaded at startup.
53  *
54  * First we must add a string to .dynstr.  Since .dynstr is in the
55  * middle of the text segment we cannot expand it as it will shift
56  * all the following instructions to different addresses in memory
57  * causing much chaos.  So we expand it and shift it up as many
58  * bytes as we expand it, so it ends on the same offset within the
59  * file.  There are no instructions above .dynstr so any movement up
60  * there is ok.  The sections above .dynstr are all accessed through
61  * the Program Header Table or .dynamic table and those pointers
62  * can be patched up easily
63  *
64  * Of course the next question is how do you keep from shifting
65  * up past the beginning of the file? Well and ELF file has as its
66  * first 0x34 bytes the Elf Header.  This is a mandatory position.
67  * Followed by that ELF files usually (ie if they are produced by
68  * gcc) have their Program Header Table (usually 0xc0 bytes) then
69  * the actual data follows that.  The Program Header Table can
70  * be anywhere in the file (*).  So we shift it to either the
71  * end of the text segment or the beginning of the data segment and
72  * patch up the entries in the Program Header Table as needed.  
73  * How do we know we can do this? There is always one memory page
74  * between the end of the text segment and the beginnig of the data
75  * segment.  So either there will be a gap of > 0xc0 bytes between
76  * the end of the text segment and the next page boundry or the start
77  * of the data segment and the previous page boundry.  Note that it
78  * is possible but highly unlikely that the Program Header Table is
79  * greater than 0xc0 bytes, though it would need to grow quite large
80  * for this to be a problem.
81  *
82  * Note that all the assumptions except the placement of the
83  * ELF Header are merely convention, not a standard.  But they are 
84  * followed by gcc and the like.
85  * 
86  * UPDATE: 17 may 2002
87  * Previously it was assumed there would be a DT_CHECKSUM entry
88  * in the dynamic table.  this is not always the case. some
89  * compilers done put this entry in.  If it is not present there
90  * is no place to put the link to the dyninstAPI runtime shared
91  * library and everything fails.  
92  * NOW: The dynamic section is moved to the start of the data 
93  * segment.  This lets the dynamic table be expanded and the 
94  * dyninstAPI library gets its own entry without overwriting a 
95  * slot in the dynamic table. 
96  *
97  * (*) The Program Header Table should be able to be located
98  * anywhere in the file and loaded to any place in memory.
99  * The Linux loader does not seem to like it if the PHT
100  * is loaded anywhere except in the text or data segment.
101  * I have not been able to find any code to support this,
102  * its all experimental evidence
103  *
104  * UPDATE: 21 March 2005
105  * The Program Header Table CANNOT be placed after the text segment
106  * with the version of libelf distributed as part of elfutils.
107  * The PHT MUST be located in the file BEFORE every section of data.
108  * To make this work, the PHT is NOT moved.  The .note section is
109  * moved to the end of the text segment (or beginning of the data segment)
110  * and the .dynstr is expanded upward as before.
111  */
112 void addLibrary::createNewElf(){
113
114         Elf32_Ehdr *oldEhdr;
115         Elf32_Phdr *oldPhdr;
116         Elf32_Shdr *oldShdr;
117         Elf_Scn *oldScn;
118         Elf_Data *oldData;
119
120         // get Ehdr
121         oldEhdr = elf32_getehdr(oldElf);
122
123         newElfFileEhdr = (Elf32_Ehdr*) new char[oldEhdr->e_ehsize];
124         memcpy(newElfFileEhdr, oldEhdr, oldEhdr->e_ehsize);
125         //fprintf(stderr," NEW ELF e_shoff: %d\n", newElfFileEhdr->e_shoff);
126
127         // get Phdr
128         oldPhdr = elf32_getphdr(oldElf);
129         
130         newElfFilePhdr = (Elf32_Phdr*) new char[oldEhdr->e_phentsize * oldEhdr->e_phnum];
131         memcpy(newElfFilePhdr, oldPhdr, oldEhdr->e_phentsize * oldEhdr->e_phnum);
132
133         newElfFileSec = (Elf_element *) new char[sizeof(Elf_element) * (oldEhdr->e_shnum + 1)];
134         memset(newElfFileSec, '\0', sizeof(Elf_element) * (oldEhdr->e_shnum + 1));
135
136         arraySize = oldEhdr->e_shnum;
137         oldScn = NULL;
138         phdrSize = oldEhdr->e_phentsize * oldEhdr->e_phnum;
139
140         for(int cnt = 0; (oldScn = elf_nextscn(oldElf, oldScn));cnt++){
141                 oldData=elf_getdata(oldScn,NULL);
142                 oldShdr = elf32_getshdr(oldScn);
143
144                 newElfFileSec[cnt].sec_hdr = new Elf32_Shdr;
145                 newElfFileSec[cnt].sec_data = new Elf_Data;
146
147           memcpy(newElfFileSec[cnt].sec_hdr, oldShdr, sizeof(Elf32_Shdr));
148           memcpy(newElfFileSec[cnt].sec_data,oldData, sizeof(Elf_Data));
149
150           if(oldData->d_buf && oldData->d_size){
151                 newElfFileSec[cnt].sec_data->d_buf = new char[oldData->d_size];
152                memcpy(newElfFileSec[cnt].sec_data->d_buf, oldData->d_buf, oldData->d_size);
153                 } 
154                 if(cnt + 1 == newElfFileEhdr->e_shstrndx) {
155                         strTabData = newElfFileSec[cnt].sec_data;
156                 }
157         }
158
159 }
160
161 void addLibrary::updateDynamic(Elf_Data *newData,unsigned int dynstrOff,unsigned int dynsymOff, unsigned int hashOff,unsigned int stringSize){
162 /*
163         for(unsigned int k =(newData->d_size/sizeof(Elf32_Dyn))-1 ; k>0;k--){
164                 memcpy( &(((Elf32_Dyn*) (newData->d_buf))[k]),&(((Elf32_Dyn*) (newData->d_buf))[k-1]),
165                                 sizeof(Elf32_Dyn));     
166         }
167         ((Elf32_Dyn*) (newData->d_buf))[0].d_tag = DT_NEEDED;
168         ((Elf32_Dyn*) (newData->d_buf))[0].d_un.d_val = libnameIndx;
169
170         //ok, if we do the above, and remove DT_NULL if below, we are reordering
171         //the _DYNAMIC table, putting libdyninstAPI_RT.so in the first position
172         //this reorders the load of the SO and moves it! once i get the
173         //dlopen problem fixed then this will be handled ok.
174 */      
175
176 #if MOVEDYNAMIC
177         char *d_buf = new char[newData->d_size +sizeof(Elf32_Dyn) ];
178
179         //fprintf(stderr," ALLOC NEW DYNAMIC: %x\n",newData->d_size +sizeof(Elf32_Dyn));
180  
181         memset(d_buf, '\0', newData->d_size +sizeof(Elf32_Dyn) ); // make them all DT_NULL
182         memcpy(d_buf, newData->d_buf, newData->d_size );
183  
184  //     delete [] newData;
185         delete  [] (char*) (newData->d_buf); //ccw 8 mar 2004
186         newData->d_buf = d_buf;
187         newData->d_size += sizeof(Elf32_Dyn);
188 #endif
189         for(unsigned int counter=0;counter<newData->d_size/sizeof(Elf32_Dyn);counter++){
190
191                 if(     ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_HASH ){ 
192                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = hashOff;
193                 }
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 = stringSize; 
204                 }
205                 /* ccw 8 mar 2004: leave DT_DEBUG as is, this allows gdb to
206                         properly access the link_map struct
207                 */
208                 /*if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_DEBUG){
209                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = 1;
210
211                 }*/
212 #if MOVEDYNAMIC
213                 if( ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag == DT_NULL) {
214                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_tag = DT_NEEDED;
215                         ((Elf32_Dyn*) (newData->d_buf))[counter].d_un.d_val = libnameIndx;
216                         counter = newData->d_size/sizeof(Elf32_Dyn)+ 1;
217                 }
218 #endif
219         }
220
221
222 }
223
224 int addLibrary::findSection(char* name){
225         
226         for(int cnt = 0 ; cnt < arraySize; cnt ++ ){
227                 if (newElfFileSec[cnt].sec_hdr && !strcmp(name, (char *)strTabData->d_buf+newElfFileSec[cnt].sec_hdr->sh_name) ) {
228                         return cnt;
229                 }
230         }
231         return -1;
232 }
233
234
235 void addLibrary::updateProgramHeaders(Elf32_Phdr *phdr, unsigned int /* dynstrOffset */){
236
237
238         //update PT_PHDR
239         //phdr[0].p_offset = newPhdrOffset;
240         //phdr[0].p_vaddr =  newPhdrAddr ;
241         //phdr[0].p_paddr = phdr[0].p_vaddr;
242
243         if(gapFlag == TEXTGAP){
244                 //update TEXT SEGMENT
245                 phdr[2].p_memsz = newTextSegmentSize;
246                 phdr[2].p_filesz = newTextSegmentSize;
247
248         } 
249         /* we have already updated the data segments filesz and memsz in  fixUpPhdrForDynamic*/
250         /*else if(gapFlag == DATAGAP){
251                 //update DATA SEGMENT
252                 phdr[3].p_memsz += phdr[0].p_filesz;
253                 phdr[3].p_filesz += phdr[0].p_filesz;
254                 //phdr[3].p_offset = newPhdrOffset;
255                 //phdr[3].p_vaddr = newPhdrAddr;
256                 //phdr[3].p_paddr = newPhdrAddr;
257         }*/
258         
259         for(int i=0;i<newElfFileEhdr->e_phnum;i++){
260                 if(phdr[i].p_type == PT_NOTE ){
261                         phdr[i].p_vaddr += (newNoteOffset - phdr[i].p_offset);
262                         phdr[i].p_paddr = phdr[i].p_vaddr; 
263                         phdr[i].p_offset = newNoteOffset;
264                         //phdr[i].p_type = PT_NULL;// 6 Mar 2005
265                 }
266                 
267         /*      if(phdr[i].p_offset && phdr[i].p_offset < dynstrOffset){
268                         phdr[i].p_offset -= libnameLen;
269                         phdr[i].p_vaddr -= libnameLen;
270                         phdr[i].p_paddr -= libnameLen;
271                 }else if(phdr[i].p_type != PT_PHDR && phdr[i].p_vaddr > newPhdrAddr){
272                         phdr[i].p_offset +=_pageSize;
273                 }
274         */
275         }       
276 #if !MOVEDYNAMIC
277
278         phdr[3].p_offset += _pageSize;
279         phdr[4].p_offset += _pageSize;
280
281 #endif
282
283
284
285
286 void addLibrary::addStr(Elf_Data *newData,Elf_Data *oldData ,char* libname){
287
288         newData->d_size += libnameLen;
289         
290         delete [] (char*) newData->d_buf;
291         
292         newData->d_buf = new char[newData->d_size];
293         memcpy(newData->d_buf, oldData->d_buf,oldData->d_size); 
294
295         memcpy(&(((char*) newData->d_buf)[newData->d_size-libnameLen]), libname, libnameLen);
296         libnameIndx = newData->d_size-libnameLen;                       
297
298 }
299
300 int addLibrary::writeNewElf(char* filename, char* /* libname */){
301
302         Elf32_Ehdr *realEhdr;
303         Elf32_Phdr *realPhdr;
304         Elf_Scn *realScn;
305         Elf32_Shdr *realShdr;
306         Elf_Data *realData, *strTabData;
307         unsigned int dynstrOffset=0;
308         unsigned int dynsymOffset=0;
309         unsigned int hashOffset=0;
310         unsigned int dynstrSize=0;
311         bool seenDynamic = false;
312         
313         int foundDynstr = 0;
314         
315         //open newElf
316         //if the following call is to open() instead of creat()
317         //and dyninst is compiled with gcc 3.0.[2|4] with -O3 
318         //this file is written as all zeros and the permissions are 
319         //odd ( u=--- g=--S o=r--)
320         
321         //if((newFd = open(filename,  O_WRONLY|O_CREAT|O_TRUNC )) ==-1){
322         //S_IRWXU is not defined in gcc < 3.0
323         if((newFd = creat(filename,0x1c0 /*S_IRWXU*/)) == -1) { 
324                 bperr("cannot creat: %s %d\n",filename,errno);
325                 switch(errno){
326                 case EACCES:
327                         bperr("EACCESS \n");
328                         break;
329                 }
330                 return -1;
331         }
332
333         if((newElf = elf_begin(newFd, ELF_C_WRITE, NULL)) == NULL){
334                 bperr(" elf_begin failed for newElf");
335                 return -1;
336         }
337
338         elf_flagelf(newElf,ELF_C_SET, ELF_F_LAYOUT);
339
340         // ehdr
341         realEhdr = elf32_newehdr(newElf);
342      memcpy(realEhdr,newElfFileEhdr , sizeof(Elf32_Ehdr));
343
344         // phdr
345         realPhdr = elf32_newphdr(newElf, realEhdr->e_phnum);
346         //fprintf(stderr," MAKING NEW PHDR: size: %d\n",realEhdr->e_phnum * realEhdr->e_phentsize);
347         memcpy((char*)realPhdr, (char*)newElfFilePhdr, realEhdr->e_phnum * realEhdr->e_phentsize);
348
349         //realEhdr ->e_phoff = newPhdrOffset;
350
351         strTabData = newElfFileSec[findSection(".shstrtab")].sec_data; 
352         //section data
353         
354         updateSymbols(newElfFileSec[findSection(".dynsym")].sec_data,
355                 newElfFileSec[findSection(".dynstr")].sec_data, 
356                 newElfFileSec[findSection(".dynamic")].sec_hdr->sh_addr );
357
358         int symTabIndex= findSection(".symtab");
359         int strTabIndex =findSection(".strtab");
360
361         if(symTabIndex != -1 && strTabIndex != -1){
362                 updateSymbols(newElfFileSec[symTabIndex].sec_data,
363                         newElfFileSec[strTabIndex].sec_data, 
364                         newElfFileSec[findSection(".dynamic")].sec_hdr->sh_addr );
365         
366
367                 updateSymbolsSectionInfo(newElfFileSec[symTabIndex].sec_data,
368                         newElfFileSec[strTabIndex].sec_data);
369
370                 updateSymbolsMovedTextSectionUp(newElfFileSec[symTabIndex].sec_data,
371              newElfFileSec[strTabIndex].sec_data,12);
372         }
373         updateSymbolsMovedTextSectionUp(newElfFileSec[findSection(".dynsym")].sec_data,
374               newElfFileSec[findSection(".dynstr")].sec_data,12);
375
376
377         for(int cnt = 0; cnt < newElfFileEhdr->e_shnum-1 ; cnt++){
378                 realScn = elf_newscn(newElf);
379                 realShdr = elf32_getshdr(realScn);
380                 realData = elf_newdata(realScn);
381
382                 // data
383                 memcpy(realShdr,newElfFileSec[cnt].sec_hdr, sizeof(Elf32_Shdr));
384                 memcpy(realData,newElfFileSec[cnt].sec_data, sizeof(Elf_Data));
385                 if(newElfFileSec[cnt].sec_data->d_buf && newElfFileSec[cnt].sec_data->d_size){
386                         realData->d_buf = new char[newElfFileSec[cnt].sec_data->d_size];
387                         memcpy(realData->d_buf, newElfFileSec[cnt].sec_data->d_buf, newElfFileSec[cnt].sec_data->d_size);
388                 }
389         
390                 //now dont shift everything down since we have already added the string
391                 /*if(!foundDynstr){
392                         realShdr->sh_offset -= libnameLen;
393                 }*/
394
395                 if( !strcmp(".dynamic", (char *)strTabData->d_buf+realShdr->sh_name) && !seenDynamic) {
396                         seenDynamic = true; 
397                         updateDynamic(realData,dynstrOffset,dynsymOffset,hashOffset,dynstrSize);
398 #if MOVEDYNAMIC
399                         realShdr->sh_size += sizeof(Elf32_Dyn);  // i added a shared library
400 #endif
401                         
402  
403                 }else if( !strcmp(".dynamic", (char *)strTabData->d_buf+realShdr->sh_name) && seenDynamic) {
404                         realShdr->sh_name = 0;
405                         realShdr->sh_type = 1;
406                         realData->d_size = realShdr->sh_size;
407                         memset(realData->d_buf, '\0', realShdr->sh_size);
408                         realShdr->sh_link--;
409                 }
410                 if( !strcmp(".dynstr", (char *)strTabData->d_buf+realShdr->sh_name) ){
411                         dynstrOffset = realShdr->sh_addr;
412                         //addStr(realData,newElfFileSec[cnt].sec_data, libname);
413                         //realShdr->sh_size += libnameLen;
414                         foundDynstr = 1;
415                         dynstrSize = realShdr->sh_size;
416                 }
417                 if( !strcmp(".dynsym", (char *)strTabData->d_buf+realShdr->sh_name) ){
418                         dynsymOffset = realShdr->sh_addr;
419                 }
420                 if( !strcmp(".hash", (char *)strTabData->d_buf+realShdr->sh_name) ){
421                         hashOffset = realShdr->sh_addr;
422                 }
423 #if MOVEDYNAMIC
424
425                 //put the address of the .dynamic section at the beginning of the .got
426                 if( !strcmp(".got", (char *)strTabData->d_buf+realShdr->sh_name) ){
427                         memcpy( (void*)realData->d_buf, (void*)&newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr, 4);
428                 }
429 #else
430 /*
431                 if(  cnt >= dataSegStartIndx ){
432                         realShdr->sh_offset += _pageSize;
433                 }
434                 
435                 if( !strcmp(".dynamic", (char *)strTabData->d_buf+realShdr->sh_name) ){
436                         realShdr->sh_link --;
437                 }
438         */
439 #endif
440
441
442                 if( (realShdr->sh_type == SHT_REL ||realShdr->sh_type == SHT_RELA) && realShdr->sh_info > 0){
443                         realShdr->sh_info--;
444                 }
445
446
447                 /*if( pastPhdr || realShdr->sh_addr >= newPhdrAddr){
448                         realShdr->sh_offset+=_pageSize;
449                         pastPhdr = 1;
450                 }*/
451 #if !MOVEDYNAMIC
452                 if( cnt > lastTextSegmentIndex){
453                         realShdr->sh_offset+=_pageSize;
454                 }
455 #endif
456
457                 //fprintf(stderr," WRITE NEW ELF %s\t\t%08x\t\t%06x\t\t%06x::\t%06x\t%06x\n",(char *)strTabData->d_buf+realShdr->sh_name,realShdr->sh_addr, realShdr->sh_offset, (unsigned int) realShdr->sh_size,newElfFileSec[cnt].sec_data, (unsigned int) newElfFileSec[cnt].sec_data->d_buf);
458
459         }
460
461         realEhdr ->e_shoff += _pageSize;        
462         //fprintf(stderr," NEW PHT LOCAL: %d\n",realEhdr ->e_phoff);
463         elf_update(newElf, ELF_C_NULL);
464
465         updateProgramHeaders(realPhdr, dynstrOffset);
466         
467         elf_update(newElf, ELF_C_WRITE);
468         return gapFlag;
469 }
470
471
472 unsigned int addLibrary::findSizeOfSegmentFromPHT(Elf32_Word type){
473         Elf32_Phdr *tmpPhdr = newElfFilePhdr;
474         Elf32_Half elements = newElfFileEhdr->e_phnum;
475         unsigned int retValue=0;
476         Elf32_Half i;
477
478         for(i =0;i< elements && tmpPhdr->p_type != type;i++){
479                 tmpPhdr++;
480         }
481         if (i != elements) {
482                 retValue = tmpPhdr->p_filesz;   
483         }
484         return retValue;
485
486
487 }
488
489 // look in the PHT for a PT_NOTE entry, return its file size
490 unsigned int addLibrary::findSizeOfNoteSection(){
491
492         return findSizeOfSegmentFromPHT(PT_NOTE);
493 }
494
495
496 // look in the PHT for a PT_DYNAMIC entry, return its file size
497 unsigned int addLibrary::findSizeOfDynamicSection(){
498
499         return findSizeOfSegmentFromPHT(PT_DYNAMIC);
500 }
501
502
503 //this moves the Note to the gap, and shifts upward
504 //everything until .dynstr.  .dynstr is expanded
505 //up, its end remains the same
506 //
507 //since the sections move we need to update the section links
508 //for .hash .dynsym .gnu.version .gnu.version_r .rel.dyn .rel.plt 
509 //(all sections after the original .note and before the new .note)
510 //
511 //return the index of the libname in the new .dynstr section
512 int addLibrary::moveNoteShiftFollowingSectionsUp(char *libname){
513
514         int oldNoteSectionIndex = findSection(".note.ABI-tag");
515         int oldDynstrSectionIndex = findSection(".dynstr");
516         int lastTextSegmentIndex = findEndOfTextSegment();
517         Elf_element noteSection;
518         libnameIndx=-1;
519         //      int libnameLen = strlen(libname)+1;
520
521         if(oldNoteSectionIndex == -1 ){
522                 // try to find .note
523                 oldNoteSectionIndex = findSection(".note");
524
525                 //really should just look up the section from the PHT
526         }
527         if(oldNoteSectionIndex == -1){
528                 //failure
529                 return -1;
530         }
531
532         memcpy(&noteSection,&(newElfFileSec[oldNoteSectionIndex]),sizeof(Elf_element));
533
534         for(int i=oldNoteSectionIndex;i<lastTextSegmentIndex;i++){
535
536                 memcpy(&(newElfFileSec[i]),&(newElfFileSec[i+1]),sizeof(Elf_element));
537
538                 // if the sh_link points to something that was shifted, move it.
539                 if( newElfFileSec[i].sec_hdr->sh_link > (unsigned) oldNoteSectionIndex && 
540           newElfFileSec[i].sec_hdr->sh_link < (unsigned) lastTextSegmentIndex)
541       {
542                         newElfFileSec[i].sec_hdr->sh_link--;
543                 }
544         }
545
546         //put the old .note section here at the end.
547         newElfFileSec[lastTextSegmentIndex]=noteSection;
548
549         //ok, now change the offset and addr for everything up through .dynstr
550         //change size of .dynstr
551         int currentOffset=noteSection.sec_hdr->sh_offset;
552         int currentAddr = noteSection.sec_hdr->sh_addr;
553         for(int i=oldNoteSectionIndex;i<oldDynstrSectionIndex;i++){
554
555                 if(i== (oldDynstrSectionIndex-1)){
556                         //the new .dynstr
557                         int oldDynstrSize = newElfFileSec[i].sec_hdr->sh_size;
558
559                         //the new size of the new .dynstr section is from the current
560                         //offset to the end of the original .dynstr section
561                         newElfFileSec[i].sec_hdr->sh_size = ((newElfFileSec[i].sec_hdr->sh_offset +
562                                         newElfFileSec[i].sec_hdr->sh_size) - currentOffset);
563
564                         if( newElfFileSec[i].sec_hdr->sh_size - oldDynstrSize    < strlen(libname)+1){
565                                 //not enough room
566                                 return -1;
567                         }
568
569                         //add the new string
570                         char *tmpBuf = (char*)newElfFileSec[i].sec_data->d_buf;
571                         int libnameLen = strlen(libname)+1;
572                         newElfFileSec[i].sec_data->d_buf = new char[(newElfFileSec[i].sec_hdr->sh_size)];
573                         newElfFileSec[i].sec_data->d_size = newElfFileSec[i].sec_hdr->sh_size;
574                         memcpy(newElfFileSec[i].sec_data->d_buf,tmpBuf ,oldDynstrSize);
575                         delete [] tmpBuf;
576                         
577                         memcpy(&(((char*) newElfFileSec[i].sec_data->d_buf)[newElfFileSec[i].sec_data->d_size-libnameLen]), 
578                                 libname, strlen(libname)+1);
579
580                         //save the index that points to the new string, the .dynamic table needs it
581                         libnameIndx = newElfFileSec[i].sec_data->d_size-libnameLen;
582                 }
583
584                 newElfFileSec[i].sec_hdr->sh_offset=currentOffset;
585                 newElfFileSec[i].sec_hdr->sh_addr = currentAddr; 
586
587                 currentOffset += newElfFileSec[i].sec_hdr->sh_size;
588                 while(currentOffset %4 !=0){
589                         currentOffset++;
590                 }
591                 currentAddr += newElfFileSec[i].sec_hdr->sh_size;
592                 while(currentAddr%4 !=0){
593                         currentAddr++;
594                 }
595
596                 //fprintf(stderr,"NEW OFFSETS AND MEM ADDR AND SIZE AND SIZE %x %x %x %x\n",newElfFileSec[i].sec_hdr->sh_offset,newElfFileSec[i].sec_hdr->sh_addr, newElfFileSec[i].sec_hdr->sh_size,newElfFileSec[i].sec_data->d_size);
597         }
598
599         int offsetIncr = 1;
600         if( gapFlag == TEXTGAP){
601                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset = newElfFileSec[lastTextSegmentIndex-1].sec_hdr->sh_offset + newElfFileSec[lastTextSegmentIndex-1].sec_hdr->sh_size;
602                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_addr = newElfFileSec[lastTextSegmentIndex-1].sec_hdr->sh_addr + newElfFileSec[lastTextSegmentIndex-1].sec_hdr->sh_size;
603                 newTextSegmentSize = newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset + newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_size;
604         }else{
605                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset = newElfFileSec[lastTextSegmentIndex+1].sec_hdr->sh_offset - newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_size;
606                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_addr = newElfFileSec[lastTextSegmentIndex+1].sec_hdr->sh_addr - newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_size;
607                 offsetIncr = -1;
608                 dataSegStartIndx--; 
609         }
610
611         while(newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset  %4 != 0){
612                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset+=offsetIncr;
613         }
614
615         newNoteOffset = newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_offset;
616
617         while(newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_addr %4 != 0){
618                 newElfFileSec[lastTextSegmentIndex].sec_hdr->sh_addr+=offsetIncr;
619         }
620
621         return libnameIndx;
622
623
624
625 int addLibrary::findIsNoteBeforeDynstr(){
626
627         int NoteSectionIndex = findSection(".note.ABI-tag");
628         int DynstrSectionIndex = findSection(".dynstr");
629
630         if (NoteSectionIndex == -1){
631                 NoteSectionIndex = findSection(".note");
632         }
633         if( NoteSectionIndex < DynstrSectionIndex){
634                 return 1;
635         }
636         return 0;
637
638         
639 }
640
641 //if we cannot edit the file (no space at the top, no space
642 //in the text/data gap etc) we return 0.
643 //otherwise we return 1 or 2, depending on if we use the
644 //text gap (1) or the data gap (2)
645 //
646 //If we cannot open the new file we return -1
647 int addLibrary::driver(Elf *elf,  char* newfilename, char *libname){
648
649         libnameLen = strlen(libname) +1;
650         oldElf = elf;   
651         _pageSize = getpagesize();
652
653         createNewElf();
654         elf_end(elf);
655         textSegEndIndx = findEndOfTextSegment();
656         dataSegStartIndx = findStartOfDataSegment();
657         checkFile(); // this sets textSideGap and dataSideGap
658
659
660         unsigned int sizeOfNoteSection = findSizeOfNoteSection();
661         int isNoteBeforeDynstr;
662
663         if( sizeOfNoteSection == 0 ){
664                 //no .note section found!
665                 isNoteBeforeDynstr = 0;
666         }else{  
667                 isNoteBeforeDynstr = findIsNoteBeforeDynstr();
668         }
669         
670         if( sizeOfNoteSection == 0 || isNoteBeforeDynstr == 0){
671                 //failure: no .note or .note not before .dynstr
672                 return -1;
673         }
674
675         if( sizeOfNoteSection < strlen(libname)+1 ){
676                 //failure: not enough space after .note is shifted up
677                 return -1;
678         }
679
680
681         if( textSideGap > sizeOfNoteSection ){
682                 gapFlag = TEXTGAP;
683         }else if (dataSideGap > (sizeOfNoteSection + newElfFileSec[findSection(".dynamic")].sec_hdr->sh_size+sizeof(Elf32_Dyn)) ){
684                 //check to see if it fits in the data segment, plus the the dynamic table
685                 //with its increased size
686                 gapFlag = DATAGAP;
687         }else{
688                 //failure: neither gap is big enough
689                 return -1;
690         }
691
692
693                 
694                 //this moves the Note to the gap, and shifts upward
695                 //everything until .dynstr.  .dynstr is expanded
696                 //up, its end remains the same
697                 int moved = moveNoteShiftFollowingSectionsUp(libname); 
698
699                 if(moved == -1){
700                         //failure;
701                         return -1;
702                 }
703
704 #if MOVEDYNAMIC
705                 moveDynamic();
706 #endif
707         
708                 gapFlag = writeNewElf(newfilename, libname);
709                 elf_end(newElf);
710         P_close(newFd); //ccw 6 jul 2003
711         return gapFlag;
712 }
713
714
715 addLibrary::addLibrary(){
716
717         newElfFileSec = NULL;
718         newElfFileEhdr = NULL;
719         newElfFilePhdr = NULL;
720 }
721
722 addLibrary::~addLibrary(){
723         if(newElfFileSec != NULL){
724                 
725                 for(unsigned int cnt = 0; cnt+1 < newElfFileEhdr->e_shnum ; cnt++){
726                         delete /*[] */ newElfFileSec[cnt].sec_hdr; //INSURE
727                         if( cnt != dataSegStartIndx ){ //this is .dynamic, dont delete twice.
728                                 if( newElfFileSec[cnt].sec_data->d_buf ){
729                                         //fprintf(stderr,"DELETING d_buf %x\n",(unsigned int)newElfFileSec[cnt].sec_data->d_buf);
730                                         delete [] (char*) newElfFileSec[cnt].sec_data->d_buf ;
731                                 }
732                                 //fprintf(stderr,"DELETING sec_data %x\n",(unsigned int)newElfFileSec[cnt].sec_data);
733                                 delete /*[]*/  newElfFileSec[cnt].sec_data; //INSURE
734                         }
735                 }
736
737                 if(newElfFileEhdr){
738                         delete [] newElfFileEhdr;
739                 }
740                 if(newElfFilePhdr){
741                         delete [] (char*) newElfFilePhdr;
742                 }
743
744                 delete [] newElfFileSec;
745         }
746
747 }
748
749 int addLibrary::checkFile(){
750         int result=0;
751         Elf32_Shdr *roDataShdr, *dataShdr;
752         unsigned int endrodata, startdata;
753
754         //is there space at the beginning?
755         
756         //must be space between 0x34 (end of the ehdr) and
757         //the text segment start.
758         
759         if(newElfFileSec[0].sec_hdr->sh_offset < (unsigned int) (sizeof(Elf32_Ehdr)+libnameLen) ){
760                 //there is not enough room
761                 gapFlag = 0;
762                 return 0;
763         }
764         roDataShdr = newElfFileSec[/*findSection(".rodata")*/ textSegEndIndx].sec_hdr;
765         dataShdr = newElfFileSec[/*findSection(".data")*/ dataSegStartIndx].sec_hdr;
766 /*
767         roDataShdr = newElfFileSec[findSection(".rodata")].sec_hdr;
768         dataShdr = newElfFileSec[findSection(".data")].sec_hdr;
769 */
770
771         endrodata = roDataShdr->sh_addr + roDataShdr->sh_size;
772
773         startdata = dataShdr -> sh_addr;
774
775         if( startdata - endrodata >= phdrSize ){
776
777                 //where to put the phdr?
778                 //find the gap between the text segment
779                 //end and the next page boundry
780                 unsigned int nextPage = endrodata >> 12;
781                 nextPage ++;
782                 nextPage = nextPage << 12;
783
784                 textSideGap = nextPage - endrodata;
785
786                 //find the gap between the data segment start
787                 //and the previous page boundry
788                 unsigned int prevPage = startdata >> 12;
789                 prevPage = prevPage << 12;
790                 dataSideGap = startdata - prevPage;
791
792                 if(textSideGap >= phdrSize ){ // i prefer the text side gap, no real reason
793                         result = TEXTGAP;
794                 }else if(dataSideGap >= phdrSize){
795                         result = DATAGAP;
796                 } 
797         }else{
798                 result = 0;
799         }
800         gapFlag = result;
801
802         return result;
803
804 }
805
806
807  unsigned int addLibrary::findEndOfTextSegment(){
808  //newElfFilePhdr
809         Elf32_Phdr *tmpPhdr = newElfFilePhdr;
810         unsigned int lastOffset;
811         unsigned int retVal=0;
812  
813         while(tmpPhdr->p_type != PT_LOAD){      
814                 //find first loadable segment
815                 //it should be the text segment
816                 tmpPhdr++;
817         }
818         lastOffset = tmpPhdr->p_offset + tmpPhdr->p_filesz;
819  
820         for(int i=0;i<arraySize && !retVal; i++){
821  
822                 if( lastOffset == newElfFileSec[i].sec_hdr->sh_offset + newElfFileSec[i].sec_hdr->sh_size){
823                         //found it!
824                         retVal = i;
825                 }
826         }
827         
828  
829         return retVal;
830         
831         
832  }
833  
834  unsigned int addLibrary::findStartOfDataSegment(){
835         Elf32_Phdr *tmpPhdr = newElfFilePhdr;
836         unsigned int firstOffset;
837         unsigned int retVal=0;
838  
839         while(tmpPhdr->p_type != PT_LOAD){      
840                 //find first loadable segment
841                 //it should be the text segment
842                 tmpPhdr++;
843         }
844         tmpPhdr++;
845         while(tmpPhdr->p_type != PT_LOAD){      
846                 //find second loadable segment
847                 //it should be the data segment
848                 tmpPhdr++;
849         }
850  
851         firstOffset = tmpPhdr->p_vaddr /*p_offset*/;
852  
853         for(int i=0;i<arraySize && !retVal; i++){
854  
855                 if( firstOffset == newElfFileSec[i].sec_hdr->sh_addr/*offset*/){
856                         //found it!
857                         retVal = i;
858                 }
859         }
860         return retVal;
861  }
862
863 void addLibrary::updateSymbolsSectionInfo(Elf_Data* symtabData,Elf_Data* /* strData */){
864
865         if(symtabData){
866               Elf32_Sym *symPtr=(Elf32_Sym*)symtabData->d_buf;
867  
868                  for(unsigned int i=0;i< symtabData->d_size/(sizeof(Elf32_Sym));i++,symPtr++){
869  
870                         if( ELF32_ST_TYPE(symPtr->st_info) == STT_SECTION){
871                                 int index = symPtr->st_shndx;
872                                 symPtr->st_value= newElfFileSec[index].sec_hdr->sh_addr;
873                         } 
874                  }
875
876         }
877 }
878  
879
880 void addLibrary::updateSymbolsMovedTextSectionUp(Elf_Data* symtabData,Elf_Data* strData,int /* oldTextIndex */){
881
882         if(symtabData && strData ) { 
883               Elf32_Sym *symPtr=(Elf32_Sym*)symtabData->d_buf;
884  
885                  for(unsigned int i=0;i< symtabData->d_size/(sizeof(Elf32_Sym));i++,symPtr++){
886  
887                         if( symPtr->st_shndx < dataSegStartIndx && symPtr->st_shndx > 1){
888                                 symPtr->st_shndx--;
889                         } 
890                  }
891         }
892
893 }
894  //This method updates the symbol table,
895  //it updates the address of _DYNAMIC
896  void addLibrary::updateSymbols(Elf_Data* symtabData,Elf_Data* strData, unsigned int dynAddr){
897
898         if(symtabData && strData ) { 
899                  Elf32_Sym *symPtr=(Elf32_Sym*)symtabData->d_buf;
900  
901                  for(unsigned int i=0;i< symtabData->d_size/(sizeof(Elf32_Sym));i++,symPtr++){
902  
903  
904                          if( !(strcmp("_DYNAMIC", (char*) strData->d_buf + symPtr->st_name))){
905                                  symPtr->st_value = dynAddr;
906                          }
907                  }
908         }
909  }
910
911
912  void addLibrary::fixUpPhdrForDynamic(){
913  
914  //change data segment
915  //change dynamic ptr
916         unsigned int dataSegSizeChange;
917         int dataSegIndex=0, dynSegIndex=0;
918         int oldDataSegStartIndx = dataSegStartIndx+1;
919
920         if(gapFlag == DATAGAP){
921
922                 oldDataSegStartIndx++;
923         }
924  
925  
926         while( newElfFilePhdr[dataSegIndex].p_vaddr != newElfFileSec[oldDataSegStartIndx].sec_hdr->sh_addr){
927                 dataSegIndex++; 
928         }
929         
930         /*fprintf(stderr,"fixUpPhdrForDynamic: %i %x %i %x\n",oldDataSegStartIndx,newElfFileSec[oldDataSegStartIndx].sec_hdr->sh_offset,
931                         dataSegStartIndx, 
932                         newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset );*/
933         dataSegSizeChange = newElfFileSec[oldDataSegStartIndx].sec_hdr->sh_offset -  /* +1 here because the .note and .dynamic sections have moved */
934                         newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset;
935         /* change data segment*/
936         newElfFilePhdr[dataSegIndex].p_offset = newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset;
937         /*fprintf(stderr," DATA SEG FILE SIZE: OLD %x INCR %x NEW %x\n",newElfFilePhdr[dataSegIndex].p_filesz,dataSegSizeChange,newElfFilePhdr[dataSegIndex].p_filesz + dataSegSizeChange);*/
938         newElfFilePhdr[dataSegIndex].p_filesz += dataSegSizeChange;
939         newElfFilePhdr[dataSegIndex].p_memsz += dataSegSizeChange;
940         newElfFilePhdr[dataSegIndex].p_vaddr =  newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr;
941         newElfFilePhdr[dataSegIndex].p_paddr =  newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr;
942
943
944         while( newElfFilePhdr[dynSegIndex].p_type != PT_DYNAMIC){
945                 dynSegIndex ++;
946         }
947         newElfFilePhdr[dynSegIndex].p_offset = newElfFileSec[dataSegStartIndx].sec_hdr->sh_offset;
948         newElfFilePhdr[dynSegIndex].p_vaddr =  newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr;
949         newElfFilePhdr[dynSegIndex].p_filesz += sizeof(Elf32_Dyn);
950         newElfFilePhdr[dynSegIndex].p_memsz += sizeof(Elf32_Dyn);//ccw 23 jun 2003
951         newElfFilePhdr[dynSegIndex].p_paddr  = newElfFileSec[dataSegStartIndx].sec_hdr->sh_addr; // ccw 8 mar 2004
952         
953  
954  }
955  
956  
957  void addLibrary::moveDynamic(){
958  
959         unsigned int oldDynamicIndex;
960         unsigned int newDynamicIndex;
961         Elf_element *updatedElfFile;
962         Elf32_Shdr tmpShdr;
963  
964         oldDynamicIndex = findSection(".dynamic");
965  
966         newDynamicIndex = dataSegStartIndx;
967  
968         updatedElfFile = (Elf_element*) new char[sizeof(Elf_element) * (newElfFileEhdr->e_shnum+1)]; 
969         memset(updatedElfFile,'\0',sizeof(Elf_element) * (newElfFileEhdr->e_shnum+1));
970  
971         arraySize ++;
972                 
973         for(unsigned int cnt = 0, newIndex = 0; cnt+1 < newElfFileEhdr->e_shnum ; cnt++, newIndex++){
974         
975                 if( cnt == newDynamicIndex ){
976                 //fprintf(stderr," cnt==newDynamicIndex %d == %d\n",cnt,newDynamicIndex);
977                         //copy in dynamic here
978  
979                         //save original info for later.
980                         memcpy( &tmpShdr, newElfFileSec[oldDynamicIndex].sec_hdr, sizeof(Elf32_Shdr));
981  
982                         memcpy( &(updatedElfFile[newIndex]), &(newElfFileSec[oldDynamicIndex]), sizeof(Elf_element));
983
984                 /*      fprintf(stderr,"UPDATE DYNAMIC: %x- %x- %x= %x\n", newElfFileSec[cnt].sec_hdr->sh_offset , 
985                                 updatedElfFile[newIndex].sec_hdr->sh_size , sizeof(Elf32_Dyn), (newElfFileSec[cnt].sec_hdr->sh_offset - 
986                                 updatedElfFile[newIndex].sec_hdr->sh_size - sizeof(Elf32_Dyn)));*/
987                         updatedElfFile[newIndex].sec_hdr->sh_offset = newElfFileSec[cnt].sec_hdr->sh_offset - 
988                                 updatedElfFile[newIndex].sec_hdr->sh_size - sizeof(Elf32_Dyn); /* increase in size */
989
990                         updatedElfFile[newIndex].sec_hdr->sh_offset += _pageSize;
991  
992                         while(updatedElfFile[newIndex].sec_hdr->sh_offset  % 0x10){
993                                  updatedElfFile[newIndex].sec_hdr->sh_offset --;
994                         }
995                         updatedElfFile[newIndex].sec_hdr->sh_addr = newElfFileSec[cnt].sec_hdr->sh_addr - 
996                                  newElfFileSec[cnt].sec_hdr->sh_offset +updatedElfFile[newIndex].sec_hdr->sh_offset - _pageSize;
997                         //fprintf(stderr, " UPDATE DYNAMIC NEW ADDR: %x\n", updatedElfFile[newIndex].sec_hdr->sh_addr);
998
999                         // new data!
1000                         //updatedElfFile[newIndex].sec_data->d_buf = new char[newElfFileSec[oldDynamicIndex].sec_data->d_size];
1001                         //memcpy(updatedElfFile[newIndex].sec_data->d_buf,newElfFileSec[oldDynamicIndex].sec_data->d_buf,newElfFileSec[oldDynamicIndex].sec_data->d_size);
1002                          
1003                         //fprintf(stderr,"ALLOC: %x\n",newElfFileSec[oldDynamicIndex].sec_data->d_size);
1004  
1005                         newIndex++;
1006                         //copy old entry to to next slot
1007                 } 
1008                 memcpy( &(updatedElfFile[newIndex]), &(newElfFileSec[cnt]), sizeof(Elf_element));
1009
1010                 //fprintf(stderr,"%d <-- %d\n",newIndex,cnt);
1011                 if(cnt == oldDynamicIndex){
1012                         //fprintf(stderr,"cnt==oldDynamicIndex %d==%d\n",cnt,oldDynamicIndex);
1013                         //reset name to zero
1014                         //allocat new secHdr
1015                         updatedElfFile[newIndex].sec_hdr = new Elf32_Shdr;//(Elf32_Shdr*) new char[sizeof(Elf32_Shdr)];
1016 /*
1017                         updatedElfFile[newIndex].sec_data = new Elf_Data;
1018                         updatedElfFile[newIndex].sec_data->d_buf = new char[tmpShdr.sh_size]; 
1019                         fprintf(stderr," ALLOC %x\n", tmpShdr.sh_size);
1020 */                      
1021                         memcpy( updatedElfFile[newIndex].sec_hdr, &tmpShdr, sizeof(Elf32_Shdr));
1022
1023                 }       
1024                 if( cnt >= newDynamicIndex){
1025                         updatedElfFile[newIndex].sec_hdr->sh_offset += _pageSize;
1026                 }
1027
1028  
1029                 if(updatedElfFile[newIndex].sec_hdr->sh_link >= newDynamicIndex){
1030                         updatedElfFile[newIndex].sec_hdr->sh_link++;
1031                 }
1032                 if(updatedElfFile[newIndex].sec_hdr->sh_info >= newDynamicIndex){
1033                         updatedElfFile[newIndex].sec_hdr->sh_info++;
1034                 }
1035  
1036         }
1037  
1038         newElfFileEhdr->e_shnum++;
1039         if(newElfFileEhdr->e_shstrndx >= newDynamicIndex){
1040                 newElfFileEhdr->e_shstrndx++;
1041         }
1042         delete [] newElfFileSec;
1043         newElfFileSec = updatedElfFile;
1044  
1045         fixUpPhdrForDynamic();
1046  }
1047
1048 #endif
1049
1050 // vim:ts=5: