Add initial support for analyzing AMDGPU binaries (#900)
[dyninst.git] / symtabAPI / src / emitWin.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include <algorithm>
32 #include "../common/src/parseauxv.h"
33 #include "Object.h"
34 #include "Object-nt.h"
35 #include "emitWin.h"
36 #include "Symtab.h"
37 #include <iostream>
38 #include <dbghelp.h>
39
40
41 using namespace Dyninst;
42 using namespace Dyninst::SymtabAPI;
43 using namespace std;
44
45
46 emitWin::emitWin(PCHAR baseaddress, Object *o_nt, void (*err_func)(const char *)){
47     base_addr =  baseaddress;
48     obj_nt = o_nt;
49         err_func_ = err_func;
50 }
51
52 PIMAGE_SECTION_HEADER emitWin::CreateSecHeader(unsigned int size, PIMAGE_SECTION_HEADER preSecHdr){
53     DWORD mem_offset, mem_size, disk_offset, disk_size;
54     PIMAGE_NT_HEADERS pNTHeader = obj_nt -> GetImageHeader();
55    
56     disk_size=PEAlign(size,pNTHeader -> OptionalHeader.FileAlignment);
57     mem_size=PEAlign(disk_size, pNTHeader->OptionalHeader.SectionAlignment);
58
59     disk_offset=PEAlign(preSecHdr->PointerToRawData+preSecHdr->SizeOfRawData,
60                 pNTHeader->OptionalHeader.FileAlignment);
61
62     mem_offset=PEAlign(preSecHdr->VirtualAddress+preSecHdr->Misc.VirtualSize,
63                 pNTHeader->OptionalHeader.SectionAlignment);
64     PIMAGE_SECTION_HEADER newSecHdr=new IMAGE_SECTION_HEADER;  
65     memset(newSecHdr,0,(size_t)sizeof(IMAGE_SECTION_HEADER));
66   
67     newSecHdr->PointerToRawData=disk_offset;
68     newSecHdr->VirtualAddress=mem_offset;
69
70     newSecHdr->SizeOfRawData=disk_size;
71     newSecHdr->Misc.VirtualSize=mem_size;
72     newSecHdr->Characteristics=0xC0000040;
73     return newSecHdr;
74 }
75
76 bool emitWin::AlignSection(PIMAGE_SECTION_HEADER p){
77     return true;
78 }
79
80 // based on the dyninst section being the last section
81 static Region *getDyninstSection(Symtab *st)
82 {
83    vector<Region*> regs;
84    st->getAllRegions(regs);
85    return regs.back();
86 }
87
88 static Offset copy_ILT_or_ALT(unsigned int idtIdx, 
89                              vector<pair<string,IMAGE_IMPORT_DESCRIPTOR> > &idt, 
90                              const vector<void*> &iltEntries, 
91                              const unsigned char *ptrDyn,
92                              Offset secOff, 
93                              Offset ptrToWrite,
94                              int addrWidth,
95                              bool isILT)
96 {
97    assert(idtIdx < idt.size());
98    if (isILT) {
99       idt[idtIdx].second.OriginalFirstThunk = secOff + ptrToWrite;
100    } else {
101       idt[idtIdx].second.FirstThunk = secOff + ptrToWrite;;
102    }
103    idtIdx++;
104
105    for (vector<void*>::const_iterator eit = iltEntries.begin();
106         eit != iltEntries.end(); 
107         eit++)
108    {
109       if (0 == (*eit) && idtIdx < idt.size()) {
110          if (isILT) {
111             idt[idtIdx].second.OriginalFirstThunk = secOff + ptrToWrite + addrWidth;
112          } else {
113             idt[idtIdx].second.FirstThunk = secOff + ptrToWrite + addrWidth;
114          }
115          idtIdx++;
116       }
117       memcpy((void*)(ptrDyn + ptrToWrite), &(*eit), addrWidth);
118       ptrToWrite += addrWidth;
119    }
120    return ptrToWrite;
121 }
122
123
124 /* Things that need to change:
125  *
126  * Tables
127  *  - Move import descriptor table even if we're not adding new libraries 
128       (orig. ILT, IAT, HNT tables are full, must point to additional entries)
129  *  - Add extra import lookup table entries (per-lib ILT's are NULL terminated)
130  *  - Add extra Hint/Name table entries (1 table for whole binary, but can split)
131  *  - Add extra import address table entries (can't move original entries)
132  *  - Add extra library names (duplicates are OK)
133  * PE Header
134  *  - fix Import (descriptor) table pointer
135  *  - fix Import address table pointer
136  */
137 bool emitWin::writeImpTable(Symtab* obj)
138 {
139    bool ret = true; 
140
141    // populate Import descriptor table with existing entries
142    vector<pair<string,IMAGE_IMPORT_DESCRIPTOR> > & idt = obj_nt->getImportDescriptorTable();
143    int origIDTSize = idt.size();
144
145    //get the dyninst section
146    Region *dynSec = getDyninstSection(obj);
147    assert(dynSec);
148
149    std::map<string, map<Offset, string> > & ref = obj_nt->getRefs();
150
151    // for each new library in ref, create new IDT entry,
152    // for each new function in ref, create new HNT entry
153    map<string, map<string, WORD> > hnt;
154    for(map<string, map<Offset, string> >::iterator lit=ref.begin(); 
155        lit != ref.end(); 
156        lit++)
157    {
158       // add IDT entry
159       IMAGE_IMPORT_DESCRIPTOR newID;
160       newID.FirstThunk = NULL;       // IAT offset,      don't know yet
161       newID.ForwarderChain=0;
162       newID.Name = NULL;             // lib name offset, don't know yet
163       newID.OriginalFirstThunk=NULL; // ILT offset,      don't know yet
164       newID.TimeDateStamp=0;
165       idt.push_back(std::pair<string, IMAGE_IMPORT_DESCRIPTOR>(lit->first, newID));
166
167       hnt[lit->first]; // add hnt entry for the library if needed 
168       map<string, map<string, WORD> >::iterator libHNT = hnt.find(lit->first);
169
170       // for each new function in ref, create new HNT entry
171       for(map<Offset, string>::iterator fit = lit->second.begin(); 
172           fit != lit->second.end(); 
173           fit++)
174       {
175          if (libHNT->second.end() == libHNT->second.find(fit->second)) {
176             // add missing HNT entry
177             (libHNT->second)[fit->second] = 0; // index hint = 0
178          }
179       }
180    }
181
182    //create space to hold the .dyninst section and updated import table
183    unsigned int numImports = 0;
184    // calculate hint/name table, number of import funcs, the concatenated length of lib names
185    unsigned int hntSize = 0;
186    unsigned int libNameSize = 0;
187    for (map<string, map<string, WORD> >::iterator hit = hnt.begin();
188         hit != hnt.end();
189         hit++)
190    {
191       numImports += hit->second.size();
192       libNameSize += hit->first.size() + 1;
193       for (map<string, WORD>::iterator fit = hit->second.begin();
194            fit != hit->second.end();
195            fit++)
196       {
197          int nameLen = fit->first.size();
198          hntSize += 2 + nameLen + 1 + ((nameLen+1) % 2); // hint + nameLen + '\0' + padding
199       }
200    }
201    unsigned int idtSize = sizeof(IMAGE_IMPORT_DESCRIPTOR) * (idt.size() + 1);
202    unsigned int iltSize = (numImports + hnt.size()) * obj->getAddressWidth();
203    unsigned int iatSize = iltSize;
204    unsigned int secSize = dynSec->getDiskSize() + idtSize + iltSize + hntSize + iatSize + libNameSize;
205    unsigned char* ptrDyn = (unsigned char*) GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, secSize);
206
207    // initialize the new .dyninst section
208    Offset ptrToWrite = 0;
209
210    // a. copy the existing section, set dynSec data pointer
211    memcpy(ptrDyn + ptrToWrite,
212           dynSec->getPtrToRawData(), 
213           dynSec->getDiskSize());
214    ptrToWrite += dynSec->getDiskSize();
215    dynSec->setPtrToRawData(ptrDyn, secSize);
216
217    // b. copy the HNT, set (ILT/IAT)->HNT pointers
218    assert(sizeof(void*) == obj->getAddressWidth());
219    vector<void*> iltEntries;
220    for (map<string, map<string, WORD> >::iterator hit = hnt.begin();
221         hit != hnt.end();
222         hit++)
223    {
224       for (map<string, WORD>::iterator fit = hit->second.begin();
225            fit != hit->second.end();
226            fit++)
227       {
228          // set ILT pointer
229          iltEntries.push_back((void*)(dynSec->getMemOffset() + ptrToWrite));
230
231          // copy hint
232          memcpy(ptrDyn + ptrToWrite,
233                 &(fit->second), 
234                 2);
235          ptrToWrite += 2;
236
237          // copy func name
238          int nameLen = fit->first.size() + 1; // include the ending \0
239          memcpy(ptrDyn + ptrToWrite,
240                 fit->first.c_str(), 
241                 nameLen);
242          ptrToWrite += nameLen;
243
244          // copy padding
245          int padLen = nameLen % 2;
246          if (padLen) { // padLen is 0 or 1, write if 1
247             ptrDyn[ptrToWrite] = '\0';
248             ptrToWrite += padLen;
249          }
250       }
251
252       // add null entry to close library ILT
253       iltEntries.push_back(0);
254    }
255
256    // c. copy the ILT, set IDT pointers
257    ptrToWrite = copy_ILT_or_ALT(origIDTSize, 
258                                 idt, 
259                                 iltEntries, 
260                                 ptrDyn,
261                                 dynSec->getMemOffset(), 
262                                 ptrToWrite, 
263                                 obj->getAddressWidth(), 
264                                 true); 
265
266    // d. copy the IAT (identical to ILT), set IDT pointers
267    Offset iatOffset = dynSec->getMemOffset() + ptrToWrite;
268    ptrToWrite = copy_ILT_or_ALT(origIDTSize, 
269                                 idt, 
270                                 iltEntries, 
271                                 ptrDyn,
272                                 dynSec->getMemOffset(), 
273                                 ptrToWrite, 
274                                 obj->getAddressWidth(), 
275                                 false); 
276    assert(iatSize == (dynSec->getMemOffset() + ptrToWrite - iatOffset));
277
278    // e. create list of library names, set IDT pointers
279    for (int idtIdx = origIDTSize; idtIdx  != idt.size(); idtIdx++) {
280       idt[idtIdx].second.Name = dynSec->getMemOffset() + ptrToWrite;
281       int nameLen = idt[idtIdx].first.size() + 1; // include terminating \0
282       memcpy(ptrDyn + ptrToWrite,
283              idt[idtIdx].first.c_str(), 
284              nameLen);
285       ptrToWrite += nameLen;
286    }
287
288    // f. copy the null-terminated IDT
289    Offset idtOffset = dynSec->getMemOffset() + ptrToWrite;
290    for (vector<pair<string,IMAGE_IMPORT_DESCRIPTOR> >::iterator dit = idt.begin(); 
291         dit != idt.end();
292         dit++)
293    {
294       memcpy(ptrDyn + ptrToWrite,
295              (void*)& dit->second, 
296              sizeof(IMAGE_IMPORT_DESCRIPTOR));
297       ptrToWrite += sizeof(IMAGE_IMPORT_DESCRIPTOR);
298    }
299    memset(ptrDyn + ptrToWrite, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));
300    ptrToWrite += sizeof(IMAGE_IMPORT_DESCRIPTOR);
301    assert(idtSize == (dynSec->getMemOffset() + ptrToWrite - idtOffset));
302
303    assert(ptrToWrite == secSize);
304
305    // fix PE header import descriptor table address & size
306    if (obj_nt->getPEHdr()->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT) {
307       obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = idtOffset;
308       obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = idtSize;
309    } else {
310       ret = false;
311    }
312
313    return ret;
314 } // end writeImpTable
315
316
317 bool emitWin::driver(Symtab *obj, std::string fName){
318         //if external references exist, write the import info.
319         if(!obj_nt->getRefs().empty())
320                 writeImpTable(obj);
321
322         Offset MoveAheadOffset=0;
323     //get the number of new added sections
324     std::vector<Region *> newregs;
325     if(!obj -> getAllNewRegions(newregs)){
326                 log_winerror(err_func_, "No new section added, no need to drive");
327         printf("No new section added, no need to drive\n");
328         return false;
329     }
330     //printf("number of new added sections is %d\n",newregs.size());
331
332     unsigned int n1 = NumOfAllowedSecInSectionTable();
333         
334     if(newregs.size() > n1){
335                 //no enough space in section table for new sections
336                 //need to use space in Dos Stub Area
337                 unsigned int n2= NumOfAllowedSecInDosHeader();
338                 if(newregs.size() > n1+n2){
339                         //can not accommandate all new sections even if steal all space in Dos Stub.
340                         log_winerror(err_func_, "no way to insert all new added sections, abort.\n");
341             printf("no way to insert all new added sections, abort.\n");
342             return false;
343                 }
344                 //need to move into Dos Stub Area
345                 isMoveAhead = true;
346                 //put n1 new section headers in section table, rest in dos stub
347                 MoveAheadOffset = SizeOfSecHeader*(newregs.size() - n1);
348                 //printf("move ahead in %lu bytes\n", MoveAheadOffset);
349
350     }
351     //there is enough space in section header table for new added sections
352     //no need to steal space in Dos Stub Area
353     else 
354                 isMoveAhead = false;
355
356     //get the set of regions which include new added sections.
357     std::vector<Region *> regs;
358     if(!(obj -> getAllRegions(regs))) {
359         printf("Failed to get regions.\n");
360         log_winerror(err_func_, "Failed to get regions.\n");
361         return false;
362     }
363
364     IMAGE_DOS_HEADER DosHeader;
365     memcpy(&DosHeader, base_addr, sizeof(IMAGE_DOS_HEADER));
366     DWORD peHdrOffset = DosHeader.e_lfanew;
367     DWORD dwDosStufOffset = sizeof(IMAGE_DOS_HEADER);
368     PIMAGE_NT_HEADERS NTHeader=new IMAGE_NT_HEADERS;
369
370     memcpy(NTHeader, base_addr + DosHeader.e_lfanew, sizeof(IMAGE_NT_HEADERS));
371     assert(NTHeader->Signature == IMAGE_NT_SIGNATURE);
372    
373     //vector of section headers
374     //including the new added sections
375     std::vector<PIMAGE_SECTION_HEADER> secHdrs;
376     PIMAGE_NT_HEADERS pehdr = obj_nt->GetImageHeader();
377    
378     //pointer of 1st section header
379     PIMAGE_SECTION_HEADER pScnHdr = (PIMAGE_SECTION_HEADER)(((char*)pehdr) +
380                                  sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
381                                  pehdr->FileHeader.SizeOfOptionalHeader);
382
383     //first, the original sections
384     for(unsigned int i=0; i<NTHeader->FileHeader.NumberOfSections; i++){
385         PIMAGE_SECTION_HEADER p=new IMAGE_SECTION_HEADER;
386         memcpy(p,pScnHdr, sizeof(IMAGE_SECTION_HEADER));
387         //printf("%d, name: %s, disk_off:%x\n",i, (const char*)p->Name, p->PointerToRawData);
388         secHdrs.push_back(p);
389         //AlignSection(p);
390         pScnHdr++;
391     }
392     //then, create section header for new added sections
393     PIMAGE_SECTION_HEADER pre = secHdrs[secHdrs.size()-1];
394     for(unsigned int i=0; i<newregs.size(); i++){
395         PIMAGE_SECTION_HEADER p = CreateSecHeader(newregs[i]->getDiskSize(), pre);
396         if((size_t)strlen(newregs[i]->getRegionName().c_str())> 8)
397             memcpy(p->Name, newregs[i]->getRegionName().c_str(),8);
398         else
399             memcpy(p->Name, newregs[i]->getRegionName().c_str(),
400             (size_t)strlen(newregs[i]->getRegionName().c_str()));
401         secHdrs.push_back(p);
402         pre = p;
403     }
404     
405     //printf("size of sec headers:%d\n", secHdrs.size());
406     for(unsigned int i=0; i<secHdrs.size(); i++){
407         printf("%s, diskOff=%x, diskSize=%x, memoff=%x, memsize=%x\n", 
408                (const char*)secHdrs[i]->Name,secHdrs[i]->PointerToRawData, 
409                secHdrs[i]->SizeOfRawData, secHdrs[i]->VirtualAddress, 
410                secHdrs[i]->Misc.VirtualSize);
411     }
412
413     //resize the last section to fit label and trap table pointer
414     PIMAGE_SECTION_HEADER lastSec = secHdrs[secHdrs.size()-1];
415     const int REWRITE_LABEL_SIZE = obj->getAddressWidth() + 16;
416     if (obj->getObject()->trapHeader()) {
417         lastSec->SizeOfRawData = PEAlign(
418             lastSec->SizeOfRawData + REWRITE_LABEL_SIZE, 
419             pehdr->OptionalHeader.FileAlignment);
420         lastSec->Misc.VirtualSize = PEAlign(
421             lastSec->SizeOfRawData + REWRITE_LABEL_SIZE, 
422             pehdr->OptionalHeader.SectionAlignment);
423     }
424
425     //calculate size of file
426     DWORD dwFileSize = lastSec->PointerToRawData + lastSec->SizeOfRawData;
427     //printf("size of file=%x", dwFileSize);
428
429     //open a file to write the image to disk
430     HANDLE hFile = CreateFileA(fName.c_str(),GENERIC_WRITE,
431                                FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
432                                CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
433
434     if(hFile == INVALID_HANDLE_VALUE){
435                 log_winerror(err_func_, "Failed to open a file to write.\n");
436         printf("Failed to open a file to write.\n");
437         return false;
438     }
439
440     PCHAR pMem = (char*)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,dwFileSize);
441     if(pMem == NULL){
442                 log_winerror(err_func_, "Failed to allocate memory space for written file\n");
443         printf("Failed to allocate memory space for written file\n");
444         return false;
445     }
446
447     // start to wrtie the file
448         Offset writeOffset = 0;
449     //retrieve the dos header from exe image
450     memcpy(pMem,&DosHeader,sizeof(IMAGE_DOS_HEADER));
451         writeOffset += sizeof(IMAGE_DOS_HEADER);
452
453         //if move ahead, do adjustment for the pe pointer
454         if(isMoveAhead)
455                 ((PIMAGE_DOS_HEADER)pMem)->e_lfanew -= MoveAheadOffset;
456
457     //write the dos stub
458     PCHAR dosStub = base_addr + sizeof(IMAGE_DOS_HEADER);
459         if(isMoveAhead){
460                 memcpy(pMem+writeOffset, dosStub, peHdrOffset-sizeof(IMAGE_DOS_HEADER)-MoveAheadOffset);
461                 writeOffset+=peHdrOffset-sizeof(IMAGE_DOS_HEADER)-MoveAheadOffset;
462         }
463         else{
464         memcpy(pMem+writeOffset, dosStub, peHdrOffset-sizeof(IMAGE_DOS_HEADER));
465                 writeOffset += peHdrOffset-sizeof(IMAGE_DOS_HEADER);
466         }
467    
468     //write the PE file header
469    
470     //write NT header
471     NTHeader->FileHeader.NumberOfSections = (WORD)regs.size();
472     //update SizeOfImage
473     NTHeader->OptionalHeader.SizeOfImage = secHdrs[secHdrs.size()-1]->VirtualAddress + 
474         secHdrs[secHdrs.size()-1]->Misc.VirtualSize;
475
476         //if move the import descriptor table, update its address
477         if(!obj_nt->getRefs().empty() && NTHeader->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT) {
478        Offset newOff = obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
479        Offset newSize = obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
480                 NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = newOff;
481                 NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = newSize;
482         printf("new import descriptor table address: %lu size: %lu\n", newOff, newSize);
483         }
484         //if move the import address table, update its address
485         if(!obj_nt->getRefs().empty() && NTHeader->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IAT) {
486        Offset newOff = obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
487        Offset newSize = obj_nt->getPEHdr()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
488                 NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = newOff;
489                 NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = newSize;
490                 printf("new import address table address: %lu size: %lu\n", newOff, newSize);
491         }
492
493     memcpy(pMem+writeOffset, NTHeader,sizeof(IMAGE_NT_HEADERS));
494     //if bound import table is not empty, update its virtual address
495     if(bit_addr != 0){
496         assert(NTHeader->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT);
497         PIMAGE_NT_HEADERS newpeHdr = (PIMAGE_NT_HEADERS)((void *)(pMem+writeOffset));
498         PIMAGE_OPTIONAL_HEADER newoptHdr = (PIMAGE_OPTIONAL_HEADER)&newpeHdr -> OptionalHeader;
499         printf("old address: 0x%x\n", newoptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress);
500         newoptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress+=sizeof(IMAGE_SECTION_HEADER);
501         printf("new address: 0x%x\n", newoptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress);
502     }
503         writeOffset += sizeof(IMAGE_NT_HEADERS);
504
505     //write section header table and section
506     //DWORD dwFirstSectionHeaderOffset = peHdrOffset + sizeof(IMAGE_NT_HEADERS);
507         DWORD dwFirstSectionHeaderOffset = writeOffset;
508     unsigned int numSecns = secHdrs.size();
509     for(unsigned int i=0; i<numSecns; i++){
510         memcpy(pMem+dwFirstSectionHeaderOffset + i*sizeof(IMAGE_SECTION_HEADER),secHdrs[i],
511             sizeof(IMAGE_SECTION_HEADER));
512         memcpy(pMem+secHdrs[i]->PointerToRawData, regs[i]->getPtrToRawData(),regs[i]->getDiskSize());
513     }
514
515     // copy trap-table header & DYNINST_REWRITE to end of last section
516     Address trapHead = obj->getObject()->trapHeader();
517     Address writeTarg = (Address) (pMem 
518         + lastSec->PointerToRawData 
519         + lastSec->SizeOfRawData 
520         - REWRITE_LABEL_SIZE);
521     memcpy((void*)writeTarg, (void*) &trapHead, obj->getAddressWidth());
522     memcpy((void*)(writeTarg + obj->getAddressWidth()), "DYNINST_REWRITE", 16);
523
524     //write bound import table info
525     if(bit_addr != 0){
526         memcpy(pMem+dwFirstSectionHeaderOffset + secHdrs.size()*sizeof(IMAGE_SECTION_HEADER),
527             (char*)(base_addr+bit_addr), bit_size);
528     }   
529
530     //move the file pointer to beginning to write
531     DWORD dwByteWritten =0;
532     SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
533     WriteFile(hFile, pMem, dwFileSize,&dwByteWritten, NULL);
534     // ------ FORCE CALCULATED FILE SIZE ------
535     SetFilePointer(hFile,dwFileSize,NULL,FILE_BEGIN);
536     SetEndOfFile(hFile);
537     CloseHandle(hFile);
538
539     GlobalFree(pMem);
540
541     return true;
542 }
543
544
545 /*In windows PE file, there are two alignments:
546  1. SectionAlignment: the alignment of section in memory
547  2. FileAlignment: the alignment of section in disk
548  */
549 //this function is used to calculated the aligned address given dwAddr.
550 //which is applicable for either case.
551 Offset emitWin::PEAlign(Offset dwAddr,Offset dwAlign)
552 {   
553     return(((dwAddr + dwAlign - 1) / dwAlign) * dwAlign);
554 }
555
556 //This function is used to calculate the maximum number of sections allowed to insert
557 //for the section header table, the usable space includes the usused space plus the dos stub area if any.
558 unsigned int emitWin::NumOfTotalAllowedSec(){
559     unsigned int unusedSpaces = 0;
560    
561     //get the PE header pointer;
562     PIMAGE_NT_HEADERS peHdrs = obj_nt -> GetImageHeader();
563     //if no phdr, the
564     if(peHdrs){
565    
566     }
567
568     return unusedSpaces;
569 }
570
571 //to calculate the number of entries that can be inserted into section header table
572 //because of the fileAlignment, there could be unused space in section header table
573 unsigned int emitWin::NumOfAllowedSecInSectionTable(){
574
575     //get base address of mapped file
576     PIMAGE_NT_HEADERS peHdr = obj_nt -> GetImageHeader();
577     IMAGE_OPTIONAL_HEADER optHdr = peHdr -> OptionalHeader;
578
579     unsigned int NumOfDataDir = optHdr.NumberOfRvaAndSizes;
580     //printf("NumOfDataDir: %lu\n", NumOfDataDir);
581     assert( NumOfDataDir == 16);
582
583     //retrieve information on bound import table
584     //which is 12th entry (IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) in data directory
585     //Note: bound import table is right after section header table and before sections
586     IMAGE_DATA_DIRECTORY bit = optHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT];
587     bit_addr = bit.VirtualAddress;
588     bit_size = bit.Size;
589
590     //printf("bound import table:0x%x, 0x%x\n", bit_addr, bit_size);
591
592     //calculate the size of space between section header table and section
593     PIMAGE_SECTION_HEADER pScnHdr = (PIMAGE_SECTION_HEADER)(((char*)peHdr) +
594                                  sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
595                                  peHdr->FileHeader.SizeOfOptionalHeader); //pointer of 1st section header
596     unsigned int nSections = peHdr->FileHeader.NumberOfSections;
597
598     DWORD dwFirstSectionHeaderOffset = ((PIMAGE_DOS_HEADER)base_addr)->e_lfanew + sizeof(IMAGE_NT_HEADERS);
599
600     DWORD dwStuffSize = pScnHdr ->PointerToRawData - (dwFirstSectionHeaderOffset + nSections*sizeof(IMAGE_SECTION_HEADER));
601
602     unsigned int ret = (dwStuffSize - bit_size)/SizeOfSecHeader;
603     //printf("extra section headers: %lu\n", ret);
604     return ret;
605
606 }
607
608 //to calculate the number of entries that can be inserted into Dos Stub area
609 //we don't care the Dos Stub, so just steal the space in that area for the additional section header
610 unsigned int emitWin::NumOfAllowedSecInDosHeader(){
611          //get base address of mapped file
612     PIMAGE_NT_HEADERS peHdr = obj_nt -> GetImageHeader();
613         //size of dos stub area
614         unsigned int size = (char*)peHdr - (base_addr+sizeof(IMAGE_DOS_HEADER));
615         unsigned int ret = size/SizeOfSecHeader;
616         //printf("extra section headers in dos stub: %lu\n", ret);
617         return ret;
618 }
619
620 void emitWin::log_winerror(void (*err_func)(const char *), const char* msg) {
621     err_func(msg);
622 }