ppc fixes
[dyninst.git] / dyninstAPI / src / parse-power.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 // $Id: image-power.C,v 1.23 2008/03/12 20:09:10 legendre Exp $
32
33 // Determine if the called function is a "library" function or a "user" function
34 // This cannot be done until all of the functions have been seen, verified, and
35 // classified
36 //
37
38 #include "common/src/Vector.h"
39 #include <unordered_map>
40 #include "common/src/Vector.h"
41 #include "parse-cfg.h"
42 #include "instPoint.h"
43 #include "image.h"
44 #include "parRegion.h"
45 #include "debug.h"
46
47 #include "debug.h"
48 #include <deque>
49 #include <set>
50 #include <algorithm>
51
52 #include "common/src/arch.h"
53
54 #include "instructionAPI/h/Instruction.h"
55 #include "instructionAPI/h/InstructionDecoder.h"
56
57 #include "mapped_object.h"
58 #include "binaryEdit.h"
59 #include "addressSpace.h"
60 #include "function.h"
61 #include "baseTramp.h"
62
63
64 using namespace Dyninst::SymtabAPI;
65
66 static const std::string LIBC_CTOR_HANDLER("__do_global_ctors_aux");
67 static const std::string LIBC_DTOR_HANDLER("__do_global_dtors_aux");
68 static const std::string DYNINST_CTOR_HANDLER("DYNINSTglobal_ctors_handler");
69 static const std::string DYNINST_CTOR_LIST("DYNINSTctors_addr");
70 static const std::string DYNINST_DTOR_HANDLER("DYNINSTglobal_dtors_handler");
71 static const std::string DYNINST_DTOR_LIST("DYNINSTdtors_addr");
72 static const std::string SYMTAB_CTOR_LIST_REL("__SYMTABAPI_CTOR_LIST__");
73 static const std::string SYMTAB_DTOR_LIST_REL("__SYMTABAPI_DTOR_LIST__");
74
75 static bool replaceHandler(func_instance *origHandler, func_instance *newHandler, 
76         int_symbol *newList, const std::string &listRelName)
77 {
78     // Add instrumentation to replace the function
79    // TODO: this should be a function replacement!
80    // And why the hell is it in parse-x86.C?
81    origHandler->proc()->replaceFunction(origHandler, newHandler);
82    // origHandler->proc()->relocate();
83     /* PatchAPI stuffs */
84    AddressSpace::patch(origHandler->proc());
85     /* End of PatchAPI stuffs */
86     
87     /* create the special relocation for the new list -- search the RT library for
88      * the symbol
89      */
90     Symbol *newListSym = const_cast<Symbol *>(newList->sym());
91
92     std::vector<Region *> allRegions;
93     if( !newListSym->getSymtab()->getAllRegions(allRegions) ) {
94         return false;
95     }
96
97     bool success = false;
98     std::vector<Region *>::iterator reg_it;
99     for(reg_it = allRegions.begin(); reg_it != allRegions.end(); ++reg_it) {
100         std::vector<relocationEntry> &region_rels = (*reg_it)->getRelocations();
101         vector<relocationEntry>::iterator rel_it;
102         for( rel_it = region_rels.begin(); rel_it != region_rels.end(); ++rel_it) {
103             if( rel_it->getDynSym() == newListSym ) {
104                 relocationEntry *rel = &(*rel_it);
105                 rel->setName(listRelName);
106                 success = true;
107             }
108         }
109     }
110
111     return success;
112 }
113 /*
114 By parsing the function that actually sets up the parameters for the OMP
115 region we discover informations such as what type of parallel region we're
116 dealing with */
117 bool parse_func::parseOMPParent(image_parRegion * /*iPar*/, int /*desiredNum*/, int & /*currentSectionNum*/ )
118 {
119 #if 0 //!defined(cap_instruction_api)
120    Address funcBegin = getOffset();
121    InstrucIter ah(funcBegin, this);
122    InstrucIter callFind(funcBegin, this);
123    int currentNum = 0;
124    int regValues[10 + 1];  /* Only care about registers 3-10 (params) */
125    Address regWriteLocations[10 + 1];
126
127    for (int i = 0; i < 11; i++)
128       regValues[i] = -1;
129   
130   
131    const char * regionFuncName = iPar->getAssociatedFunc()->symTabName().c_str();
132
133    while (callFind.hasMore())
134    {
135       if( callFind.isACallInstruction() ||
136           callFind.isADynamicCallInstruction() )
137       {
138          bool isAbsolute = false;
139          Address target = callFind.getBranchTargetAddress(&isAbsolute);
140          image * im = img();
141
142          parse_func *ppdf = im->findFuncByEntry(target);
143
144          if (ppdf != NULL)
145          {
146             if (strstr(ppdf->symTabName().c_str(),regionFuncName)!=NULL)
147                return 0;
148          }
149       }
150       callFind++;
151    }
152
153    while (ah.hasMore())
154    {
155       if( ah.isRegConstantAssignment(regValues, regWriteLocations) ) /* Record param values */
156       { }
157       else if( ah.isACallInstruction() ||
158                ah.isADynamicCallInstruction() )
159       {
160           
161          bool isAbsolute = false;
162          Address target = ah.getBranchTargetAddress(&isAbsolute);
163           
164           
165          /* Finding Out if the call is to OpenMP Functions */
166           
167          /* Return one of the following 
168             OMP_PARALLEL, OMP_DO_FOR, OMP_SECTIONS, OMP_SINGLE, 
169             OMP_PAR_DO, OMP_PAR_SECTIONS, OMP_MASTER, OMP_CRITICAL,
170             OMP_BARRIER, OMP_ATOMIC, OMP_FLUSH, OMP_ORDERED */
171          image * im = img();
172          parse_func *ppdf = im->findFuncByEntry(target);
173           
174          if (ppdf != NULL)
175          {
176             if (strstr(ppdf->symTabName().c_str(),"_TPO_linkage")!=NULL
177                 && ( strstr(ppdf->symTabName().c_str(), "ParRegionSetup")!= NULL
178                      || strstr(ppdf->symTabName().c_str(), "WSDoSetup")     != NULL
179                      || strstr(ppdf->symTabName().c_str(), "WSSectSetup")   != NULL
180                      || strstr(ppdf->symTabName().c_str(), "SingleSetup")   != NULL                
181                      || strstr(ppdf->symTabName().c_str(), "ParallelDoSetup")!=NULL             
182                      || strstr(ppdf->symTabName().c_str(), "WSSectSetup")   != NULL))               
183             {
184
185                if (currentNum != desiredNum)
186                   currentNum++;
187                else
188                {
189                   /* Standard outlined function */
190                   if (strstr(ppdf->symTabName().c_str(), "ParRegionSetup")!=NULL)
191                      iPar->setRegionType(OMP_PARALLEL);
192                       
193                   /* Standard outlined function */
194                   else if(strstr(ppdf->symTabName().c_str(), "WSDoSetup")!=NULL)
195                   {                     
196                      iPar->setRegionType(OMP_DO_FOR);
197                      iPar->setClause("NUM_ITERATIONS",regValues[6]); 
198                      iPar->setClause("SCHEDULE",regValues[7]);
199                      iPar->setClause("CHUNK_SIZE", regValues[8]);
200                      iPar->setClauseLoc("CHUNK_SIZE", regWriteLocations[8]);
201                      iPar->setClauseLoc("SCHEDULE", regWriteLocations[7]);
202                   }
203                       
204                   /* Standard outlined function */
205                   else if(strstr(ppdf->symTabName().c_str(), "WSSectSetup")!=NULL)
206                   {
207                      iPar->setRegionType(OMP_SECTIONS);
208                      iPar->setClause("NUM_SECTIONS",regValues[5]);
209                           
210                      currentSectionNum++;
211                           
212                      if (currentSectionNum == regValues[5])
213                         currentSectionNum = 0;
214                   }
215                       
216                   /* Standard outlined function */
217                   else if(strstr(ppdf->symTabName().c_str(), "SingleSetup")!=NULL)                  
218                      iPar->setRegionType(OMP_SINGLE);
219                       
220                   /* Standard outlined function */
221                   else if(strstr(ppdf->symTabName().c_str(), "ParallelDoSetup")!=NULL)
222                   {                 
223                      iPar->setRegionType(OMP_PAR_DO);
224                      iPar->setClause("NUM_ITERATIONS",regValues[6]); 
225                      iPar->setClause("SCHEDULE",regValues[7]);
226                      iPar->setClause("CHUNK_SIZE", regValues[8]);
227                      iPar->setClauseLoc("CHUNK_SIZE", regWriteLocations[8]);
228                      iPar->setClauseLoc("SCHEDULE", regWriteLocations[7]);
229                   }
230                   /* Standard outlined function */
231                   else if(strstr(ppdf->symTabName().c_str(), "WSSectSetup")!=NULL)                  
232                      iPar->setRegionType(OMP_PAR_SECTIONS);
233                   else                
234                   {
235                      ah++;
236                      continue;
237                           
238                   }/* End Checking Different Directive Types */
239
240                   iPar->decodeClauses(regValues[3]);
241                   iPar->setParentFunc(this);
242
243                   parRegionsList.push_back(iPar);
244
245                   if (iPar->getRegionType() == OMP_DO_FOR || 
246                       iPar->getRegionType() == OMP_PAR_DO)
247                      return true;
248                   else
249                      return false;
250                     
251                }                
252             } 
253          } 
254       }
255       ah++;
256    }
257    return true;
258 #else
259 //#warning "convert to IAPI!"
260     return false;
261 #endif
262 }
263
264
265
266         
267 std::string parse_func::calcParentFunc(const parse_func * imf,
268                                     pdvector<image_parRegion *> &/*pR*/)
269 {
270   /* We need to figure out the function that called the outlined
271      parallel region function.  We do this by chopping off the
272      last @OL@number */
273    const char * nameStart = imf->prettyName().c_str();
274    const char * nameEnd = strrchr(nameStart, '@');
275    int strSize = nameEnd - nameStart - 3;
276    
277    /* Make sure that the shortened string is not of size 0,
278       this would happen if a function started with @ or if there
279       was less than two characters between the beginning and @
280       This wouldn't happen for OpenMP functions, but might for imposters*/
281    if (strSize > 0)
282    {
283       char tempBuf[strlen(nameStart)];
284       strncpy(tempBuf, nameStart, strSize);
285       tempBuf[strSize] = '\0';
286       std::string tempPDS(tempBuf);
287       return tempPDS;
288    }
289    else   /* if it starts with @ just return the full function as its parent, we'll sort it out later */
290    {
291       std::string tempPDS(nameStart);
292       return tempPDS;
293    }
294 }
295
296
297 void parse_func::parseOMP(image_parRegion * parReg, parse_func * parentFunc, int & currentSectionNum)
298 {  
299   /* Each region is contained in a function, for the worksharing constructs
300      usually the parralel region encompasses the entire function 
301      The "desiredNum" variable is the desired construct we want to "skip" to
302      when we parse the parent function, which we do whenever we encounter
303      a new outlined function */
304   
305    int desiredNum = 0;
306        
307   /* This will fill in the directive type and all possible clauses 
308      Multiple section numbers can occur with only one call to a section setup
309      function in the parent function, so we need to always offset the desired 
310      region we are looking for with the current section number we are on*/
311       
312    int lastSecSize = 0;  // the number of sections in the most recent sections construct  
313    int totalSectionGroups = 0; // the number of sections constructs encountered (in source), 
314                                // not the number of total sections
315
316
317   /* First, we increment the desired num for each region we've already
318      parsed from the parent function.  A parent function can spawn multiple
319      outlined functions, so we don't want to mix up already parsed ones */
320    for(unsigned a = 0; a < parentFunc->parRegions().size();a++)
321    {              
322       image_parRegion * tempReg = parentFunc->parRegions()[a];
323       
324       if (tempReg->getRegionType() == OMP_PARALLEL ||
325           tempReg->getRegionType() == OMP_DO_FOR ||
326           tempReg->getRegionType() == OMP_PAR_DO ||
327           tempReg->getRegionType() == OMP_PAR_SECTIONS ||
328           tempReg->getRegionType() == OMP_SINGLE )
329       {
330          desiredNum++;
331       }
332
333       /* For the sections, we can't just count the number of section constructs
334          we run into, since multiple outlined functions line up to one section construct */
335       if (tempReg->getRegionType() == OMP_SECTIONS)
336       {
337          lastSecSize = tempReg->getClause("NUM_SECTIONS");
338          a += (lastSecSize-1);
339          totalSectionGroups++;
340       }
341    }
342    
343    
344    // if the currentSectionNum is not zero, it means there are still more outlined functions
345    // for a single section construct still out there, so we don't count the current section towards the total
346    if (currentSectionNum != 0)
347    {
348       totalSectionGroups--;
349    }
350    
351    // sets the last instruction of the region
352    //parReg->setLastInsn(get_address() + get_size());
353    // XXX this is equivalent to the above, but is it right?
354    //     it seems to be after the last instruction
355    Address last = extents().back()->end();
356    parReg->setLastInsn(last);
357    
358    // we need to parse the parent function to get all the information about the region, mostly for worksharing constructs
359    bool hasLoop = parentFunc->parseOMPParent(parReg, desiredNum + totalSectionGroups, currentSectionNum);           
360    
361    // we parse the outlined function to look for inlined constructs like "Master" and "Ordered"
362    parseOMPFunc(hasLoop);
363 }         
364
365 void parse_func::parseOMPFunc(bool /*hasLoop*/)
366 {
367    if (OMPparsed_)
368       return;
369    OMPparsed_ = true;
370   
371    /* We parse the parent to get info if we are in an outlined function, but there can be some
372       inlined functions we might miss out on if we don't check those out too */
373    int regValues[10 + 1];  /* Only care about registers 3-10 (params) */
374    for (int i = 0; i < 11; i++)
375       regValues[i] = -1;
376   
377 #if 0//!defined(cap_instruction_api)
378    Address funcBegin = getOffset();
379    InstrucIter ah(funcBegin, this);
380    while (ah.hasMore())
381    {
382       if( /*ah.isRegConstantAssignment(regValues)*/ 0 ) /* Record param values */
383       { }
384       // Loop parsing for the Do/For constructs
385       else if( hasLoop && ah.isACondBDZInstruction())
386       {
387          InstrucIter ah2(ah.getCurrentAddress(), this);
388           
389          Address startLoop = ah.getCurrentAddress() + 4;
390           
391          while (ah2.hasMore())
392          {
393             if (ah2.isACondBDNInstruction())
394             {
395                 addParRegion(startLoop, ah2.getCurrentAddress(), OMP_DO_FOR_LOOP_BODY);
396                break;
397             }
398             ah2++;
399          }
400       }
401       // Here we get all the info for the inlined constructs that don't have outlined functions
402       else if( ah.isACallInstruction() ||
403                ah.isADynamicCallInstruction() )
404       {
405          bool isAbsolute = false;
406          Address target = ah.getBranchTargetAddress(&isAbsolute);
407           
408           
409          /* Finding Out if the call is to OpenMP Functions */
410           
411          /* Return one of the following 
412             OMP_PARALLEL, OMP_DO_FOR, OMP_SECTIONS, OMP_SINGLE, 
413             OMP_PAR_DO, OMP_PAR_SECTIONS, OMP_MASTER, OMP_CRITICAL,
414             OMP_BARRIER, OMP_ATOMIC, OMP_FLUSH, OMP_ORDERED */
415          image * im = img();
416          parse_func *ppdf = im->findFuncByEntry(target);
417          if (ppdf != NULL)
418          {
419             if (strstr(ppdf->symTabName().c_str(),"_xlsmp")!=NULL)
420             {
421                /* Section consists of only one instruction, call to "_xlsmpBarrier_TPO" */
422                if(strstr(ppdf->symTabName().c_str(), "Barrier")!=NULL)
423                {
424                    addParRegion(ah.getCurrentAddress(), ah.getCurrentAddress()+4, OMP_BARRIER);
425                }
426                /* Section begins with "BeginOrdered, ends with EndOrdered" */
427                else if(strstr(ppdf->symTabName().c_str(), "BeginOrdered") !=NULL)
428                {
429                       
430                   InstrucIter ah2(ah.getCurrentAddress(), this);
431                   while (ah2.hasMore())
432                   {
433                      if( ah2.isACallInstruction() ||
434                          ah2.isADynamicCallInstruction() )
435                      {
436                         Address target2 = ah2.getBranchTargetAddress(&isAbsolute);
437                               
438                         parse_func *ppdf2 = im->findFuncByEntry(target2);
439                         if (ppdf2 != NULL)
440                         {
441                            if(strstr(ppdf2->symTabName().c_str(), "EndOrdered") !=NULL)
442                               break;
443                         }
444                      }
445                      ah2++;
446                   }
447                   addParRegion(ah.getCurrentAddress(), ah2.getCurrentAddress(), OMP_ORDERED);
448                   parRegionsList.push_back(iPar);
449                }
450                /* Master construct */
451                else if(strstr(ppdf->symTabName().c_str(), "Master") !=NULL)
452                {
453                    addParRegion(ah.getCurrentAddress(), ah.getCurrentAddress() + 0x04, OMP_MASTER);
454                }
455                /* Flush construct */
456                else if(strstr(ppdf->symTabName().c_str(), "Flush") !=NULL)
457                {
458                    addParRegion(ah.getCurrentAddress(), ah.getCurrentAddress() + 0x04, OMP_FLUSH);
459                }
460                /* Critical Construct, Starts with GetDefaultSLock, ends with RelDefaultSLock */
461                else if(strstr(ppdf->symTabName().c_str(), "GetDefaultSLock") != NULL)
462                {
463                   InstrucIter ah2(ah.getCurrentAddress(), this);
464                   while (ah2.hasMore())
465                   {
466                      if( ah2.isACallInstruction() ||
467                          ah2.isADynamicCallInstruction() )
468                      {
469                         Address target2 = ah2.getBranchTargetAddress(&isAbsolute);
470                               
471                         parse_func *ppdf2 = im->findFuncByEntry(target2);
472                         if (ppdf2 != NULL)
473                         {
474                            if(strstr(ppdf2->symTabName().c_str(), "RelDefaultSLock") !=NULL)
475                               break;
476                         }
477                      }
478                      ah2++;
479                   }
480                   addParRegion(ah.getCurrentAddress(), ah2.getCurrentAddress(), OMP_CRITICAL);
481                }
482                /*Atomic Construct,  Begins with GetAtomicLock, ends with RelAtomicLock */
483                else if(strstr(ppdf->symTabName().c_str(), "GetAtomicLock") != NULL)
484                {
485                   image_parRegion * iPar = new image_parRegion(ah.getCurrentAddress(),this);
486                   iPar->setRegionType(OMP_ATOMIC);
487
488                   InstrucIter ah2(ah.getCurrentAddress(), this);
489                   while (ah2.hasMore())
490                   {
491                      if( ah2.isACallInstruction() ||
492                          ah2.isADynamicCallInstruction() )
493                      {
494                         Address target2 = ah2.getBranchTargetAddress(&isAbsolute);
495                               
496                         parse_func *ppdf2 = im->findFuncByEntry(target2);
497                         if (ppdf2 != NULL)
498                         {
499                            if(strstr(ppdf2->symTabName().c_str(), "RelDefaultSLock") !=NULL)
500                               break;
501                         }
502                      }
503                      ah2++;
504                   }
505                   iPar->setLastInsn(ah2.getCurrentAddress());
506                       
507                   iPar->setParentFunc(this); // when not outlined, parent func will be same as regular
508                   iPar->setLastInsn(ah.getCurrentAddress() + 0x4); //Only one instruction long
509                       
510                   parRegionsList.push_back(iPar);
511                }
512                else
513                {
514                }/* End Checking Different Directive Types */
515                  
516             }
517          }
518       }
519       ah++;
520    }
521 #endif
522 }
523
524 /* This does a linear scan to find out which registers are used in the function,
525    it then stores these registers so the scan only needs to be done once.
526    It returns true or false based on whether the function is a leaf function,
527    since if it is not the function could call out to another function that
528    clobbers more registers so more analysis would be needed */
529 void parse_func::calcUsedRegs()
530 {
531    if (usedRegisters != NULL)
532       return; 
533    else
534    {
535       usedRegisters = new parse_func_registers();
536     using namespace Dyninst::InstructionAPI;
537     std::set<RegisterAST::Ptr> writtenRegs;
538
539     auto bl = blocks();
540     auto curBlock = bl.begin();
541     for( ; curBlock != bl.end(); ++curBlock) 
542     {
543         InstructionDecoder d(getPtrToInstruction((*curBlock)->start()),
544         (*curBlock)->size(),
545         isrc()->getArch());
546         Instruction::Ptr i;
547         while(i = d.decode())
548         {
549             i->getWriteSet(writtenRegs);
550         }
551     }
552     for(std::set<RegisterAST::Ptr>::const_iterator curReg = writtenRegs.begin();
553         curReg != writtenRegs.end();
554        ++curReg)
555     {
556         MachRegister r = (*curReg)->getID();
557         if((r & ppc32::GPR) && (r <= ppc32::r13))
558         {
559             usedRegisters->generalPurposeRegisters.insert(r & 0xFFFF);
560         }
561         else if(((r & ppc32::FPR) && (r <= ppc32::fpr13)) ||
562                   ((r & ppc32::FSR) && (r <= ppc32::fsr13)))
563         {
564             usedRegisters->floatingPointRegisters.insert(r & 0xFFFF);
565         }
566     }
567    }
568    return;
569 }
570
571 #include "binaryEdit.h"
572 #include "addressSpace.h"
573 #include "function.h"
574 #include "baseTramp.h"
575 #include "image.h"
576
577 using namespace Dyninst::SymtabAPI;
578 /*
579  * Static binary rewriting support
580  *
581  * Some of the following functions replace the standard ctor and dtor handlers
582  * in a binary. Currently, these operations only work with binaries linked with
583  * the GNU toolchain. However, it should be straightforward to extend these
584  * operations to other toolchains.
585  */
586
587 bool BinaryEdit::doStaticBinarySpecialCases() {
588     Symtab *origBinary = mobj->parse_img()->getObject();
589
590     /* Special Case 1: Handling global constructor and destructor Regions
591      *
592      * Replace global ctors function with special ctors function,
593      * and create a special relocation for the ctors list used by the special
594      * ctors function
595      *
596      * Replace global dtors function with special dtors function,
597      * and create a special relocation for the dtors list used by the special
598      * dtors function
599      */
600
601     // First, find all the necessary symbol info.
602
603     func_instance *globalCtorHandler = mobj->findGlobalConstructorFunc(LIBC_CTOR_HANDLER);
604     if( !globalCtorHandler ) {
605         logLine("failed to find libc constructor handler\n");
606         fprintf (stderr, "failed to find libc constructor handler\n");
607         return false;
608     }
609
610     func_instance *dyninstCtorHandler = findOnlyOneFunction(DYNINST_CTOR_HANDLER);
611     if( !dyninstCtorHandler ) {
612         logLine("failed to find Dyninst constructor handler\n");
613         fprintf (stderr,"failed to find Dyninst constructor handler\n");
614         return false;
615     }
616
617     func_instance *globalDtorHandler = mobj->findGlobalDestructorFunc(LIBC_DTOR_HANDLER);
618     if( !globalDtorHandler ) {
619         logLine ("failed to find libc destructor handler\n");
620         fprintf (stderr,"failed to find libc destructor handler\n");
621         return false;
622     }
623
624     func_instance *dyninstDtorHandler = findOnlyOneFunction(DYNINST_DTOR_HANDLER);
625     if( !dyninstDtorHandler ) {
626         logLine("failed to find Dyninst destructor handler\n");
627         fprintf (stderr,"failed to find Dyninst destructor handler\n");
628         return false;
629     }
630
631     int_symbol ctorsListInt;
632     int_symbol dtorsListInt;
633     bool ctorFound = false, dtorFound = false;
634     std::vector<BinaryEdit *>::iterator rtlib_it;
635     for(rtlib_it = rtlib.begin(); rtlib_it != rtlib.end(); ++rtlib_it) {
636         if( (*rtlib_it)->getSymbolInfo(DYNINST_CTOR_LIST, ctorsListInt) ) {
637             ctorFound = true;
638             if( dtorFound ) break;
639         }
640
641         if( (*rtlib_it)->getSymbolInfo(DYNINST_DTOR_LIST, dtorsListInt) ) {
642             dtorFound = true;
643             if( ctorFound ) break;
644         }
645     }
646     if( !ctorFound ) {
647          logLine("failed to find ctors list symbol\n");
648          fprintf (stderr,"failed to find ctors list symbol\n");
649          return false;
650     }
651
652     if( !dtorFound ) {
653         logLine("failed to find dtors list symbol\n");
654         fprintf (stderr,"failed to find dtors list symbol\n");
655         return false;
656     }
657
658     /*
659      * Replace the libc ctor and dtor handlers with our special handlers
660      */
661
662     if( !replaceHandler(globalCtorHandler, dyninstCtorHandler,
663                 &ctorsListInt, SYMTAB_CTOR_LIST_REL) ) {
664         logLine("Failed to replace libc ctor handler with special handler");
665         fprintf (stderr,"Failed to replace libc ctor handler with special handler");
666         return false;
667     }else{
668         inst_printf("%s[%d]: replaced ctor function %s with %s\n",
669                 FILE__, __LINE__, LIBC_CTOR_HANDLER.c_str(),
670                 DYNINST_CTOR_HANDLER.c_str());
671     }
672
673     if( !replaceHandler(globalDtorHandler, dyninstDtorHandler,
674                 &dtorsListInt, SYMTAB_DTOR_LIST_REL) ) {
675         logLine("Failed to replace libc dtor handler with special handler");
676         fprintf (stderr,"Failed to replace libc dtor handler with special handler");
677         return false;
678     }else{
679         inst_printf("%s[%d]: replaced dtor function %s with %s\n",
680                 FILE__, __LINE__, LIBC_DTOR_HANDLER.c_str(),
681                 DYNINST_DTOR_HANDLER.c_str());
682     }
683
684     /*
685      * Special Case 2: Issue a warning if attempting to link pthreads into a binary
686      * that originally did not support it or into a binary that is stripped. This
687      * scenario is not supported with the initial release of the binary rewriter for
688      * static binaries.
689      *
690      * The other side of the coin, if working with a binary that does have pthreads
691      * support, pthreads needs to be loaded.
692      */
693
694     bool isMTCapable = isMultiThreadCapable();
695     bool foundPthreads = false;
696
697     vector<Archive *> libs;
698     vector<Archive *>::iterator libIter;
699     if( origBinary->getLinkingResources(libs) ) {
700         for(libIter = libs.begin(); libIter != libs.end(); ++libIter) {
701             if( (*libIter)->name().find("libpthread") != std::string::npos ||
702                 (*libIter)->name().find("libthr") != std::string::npos )
703             {
704                 foundPthreads = true;
705                 break;
706             }
707         }
708     }
709
710     if( foundPthreads && (!isMTCapable || origBinary->isStripped()) ) {
711         fprintf(stderr,
712             "\nWARNING: the pthreads library has been loaded and\n"
713             "the original binary is not multithread-capable or\n"
714             "it is stripped. Currently, the combination of these two\n"
715             "scenarios is unsupported and unexpected behavior may occur.\n");
716     }else if( !foundPthreads && isMTCapable ) {
717         fprintf(stderr,
718             "\nWARNING: the pthreads library has not been loaded and\n"
719             "the original binary is multithread-capable. Unexpected\n"
720             "behavior may occur because some pthreads routines are\n"
721             "unavailable in the original binary\n");
722     }
723
724     /* 
725      * Special Case 3:
726      * The RT library has some dependencies -- Symtab always needs to know
727      * about these dependencies. So if the dependencies haven't already been
728      * loaded, load them.
729      */
730
731     vector<Archive *> libs1;
732     vector<Archive *>::iterator libIter1;
733     bool loadLibc = true;
734     if( origBinary->getLinkingResources(libs1) ) {
735         for(libIter1 = libs1.begin(); libIter1 != libs1.end(); ++libIter1) {
736                 if( (*libIter1)->name().find("libc.a") != std::string::npos ) {
737                         loadLibc = false;
738                 }
739         }
740     }
741
742     if( loadLibc ) {
743        std::map<std::string, BinaryEdit *> res; 
744        openResolvedLibraryName("libc.a", res);
745         std::map<std::string, BinaryEdit *>::iterator bedit_it;
746         for(bedit_it = res.begin(); bedit_it != res.end(); ++bedit_it) {
747             if( bedit_it->second == NULL ) {
748                 logLine("Failed to load DyninstAPI_RT library dependency (libc.a)");
749                 fprintf (stderr,"Failed to load DyninstAPI_RT library dependency (libc.a)");
750                 return false;
751             }
752         }
753     }
754
755     return true;
756 }
757
758 func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorHandler) {
759     using namespace Dyninst::InstructionAPI;
760
761     const pdvector<func_instance *> *funcs = findFuncVectorByMangled(ctorHandler);
762     if( funcs != NULL ) {
763         return funcs->at(0);
764     }
765
766     /* If the symbol isn't found, try looking for it in a call instruction in
767      * the .init section
768      *
769      * On Linux, the instruction sequence is:
770      * ...
771      * some instructions
772      * ...
773      * call call_gmon_start
774      * call frame_dummy
775      * call ctor_handler
776      *
777      * On FreeBSD, the instruction sequence is:
778      * ...
779      * some instructions
780      * ...
781      * call frame_dummy
782      * call ctor_handler
783      */
784     Symtab *linkedFile = parse_img()->getObject();
785     Region *initRegion = NULL;
786     if( !linkedFile->findRegion(initRegion, ".init") ) {
787         vector<Dyninst::SymtabAPI::Function *> symFuncs;
788         if( linkedFile->findFunctionsByName(symFuncs, "_init") ) {
789             initRegion = symFuncs[0]->getRegion();
790         }else{
791             logLine("failed to locate .init Region or _init function\n");
792             return NULL;
793         }
794     }
795
796     if( initRegion == NULL ) {
797         logLine("failed to locate .init Region or _init function\n");
798         return NULL;
799     }
800
801     // Search for last of a fixed number of calls
802 #if defined(os_freebsd)
803     const unsigned CTOR_NUM_CALLS = 2;
804 #else
805     const unsigned CTOR_NUM_CALLS = 3;
806 #endif
807
808     Address ctorAddress = 0;
809     unsigned bytesSeen = 0;
810     unsigned numCalls = 0;
811     const unsigned char *p = reinterpret_cast<const unsigned char *>(initRegion->getPtrToRawData());
812
813     InstructionDecoder decoder(p, initRegion->getDiskSize(),
814         parse_img()->codeObject()->cs()->getArch()); 
815
816     Instruction::Ptr curInsn = decoder.decode();
817     while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() &&
818           bytesSeen < initRegion->getDiskSize()) 
819     {
820         InsnCategory category = curInsn->getCategory();
821         if( category == c_CallInsn ) {
822             numCalls++;
823         }
824         if( numCalls < CTOR_NUM_CALLS ) {
825             bytesSeen += curInsn->size();
826             curInsn = decoder.decode();
827         }
828     }
829
830     if( numCalls != CTOR_NUM_CALLS ) {
831         logLine("heuristic for finding global constructor function failed\n");
832         return NULL;
833     }
834
835     Address callAddress = initRegion->getMemOffset() + bytesSeen;
836
837     RegisterAST thePC = RegisterAST(
838         Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
839
840     Expression::Ptr callTarget = curInsn->getControlFlowTarget();
841     if( !callTarget.get() ) {
842         logLine("failed to find global constructor function\n");
843         return NULL;
844     }
845     callTarget->bind(&thePC, Result(s64, callAddress));
846
847     Result actualTarget = callTarget->eval();
848     if( actualTarget.defined ) {
849         ctorAddress = actualTarget.convert<Address>();
850     }else{
851         logLine("failed to find global constructor function\n");
852         return NULL;
853     }
854
855     if( !ctorAddress || !parse_img()->codeObject()->cs()->isValidAddress(ctorAddress) ) {
856         logLine("invalid address for global constructor function\n");
857         return NULL;
858     }
859
860     func_instance *ret;
861     if( (ret = findFuncByEntry(ctorAddress)) == NULL ) {
862         logLine("unable to create representation for global constructor function\n");
863         return NULL;
864     }
865
866     inst_printf("%s[%d]: set global constructor address to 0x%lx\n", FILE__, __LINE__,
867             ctorAddress);
868
869     return ret;
870 }
871
872 func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHandler) {
873     using namespace Dyninst::InstructionAPI;
874
875     const pdvector<func_instance *> *funcs = findFuncVectorByMangled(dtorHandler);
876     if( funcs != NULL ) {
877         return funcs->at(0);
878     }
879
880     /*
881      * If the symbol isn't found, try looking for it in a call in the
882      * .fini section. It is the last call in .fini.
883      *
884      * The pattern is:
885      *
886      * _fini:
887      *
888      * ... some code ...
889      *
890      * call dtor_handler
891      *
892      * ... prologue ...
893      */
894     Symtab *linkedFile = parse_img()->getObject();
895     Region *finiRegion = NULL;
896     if( !linkedFile->findRegion(finiRegion, ".fini") ) {
897         vector<Dyninst::SymtabAPI::Function *> symFuncs;
898         if( linkedFile->findFunctionsByName(symFuncs, "_fini") ) {
899             finiRegion = symFuncs[0]->getRegion();
900         }else{
901             logLine("failed to locate .fini Region or _fini function\n");
902             return NULL;
903         }
904     }
905
906     if( finiRegion == NULL ) {
907         logLine("failed to locate .fini Region or _fini function\n");
908         return NULL;
909     }
910
911     // Search for last call in the function
912     Address dtorAddress = 0;
913     unsigned bytesSeen = 0;
914     const unsigned char *p = reinterpret_cast<const unsigned char *>(finiRegion->getPtrToRawData());
915
916     InstructionDecoder decoder(p, finiRegion->getDiskSize(),
917         parse_img()->codeObject()->cs()->getArch());
918
919     Instruction::Ptr lastCall;
920     Instruction::Ptr curInsn = decoder.decode();
921
922     while(curInsn && curInsn->isValid() &&
923           bytesSeen < finiRegion->getDiskSize()) 
924     {
925         InsnCategory category = curInsn->getCategory();
926         if( category == c_CallInsn ) {
927             lastCall = curInsn;
928             break;
929         }
930
931         bytesSeen += curInsn->size();
932         curInsn = decoder.decode();
933     }
934
935     if( !lastCall.get() || !lastCall->isValid() ) {
936         logLine("heuristic for finding global destructor function failed\n");
937         return NULL;
938     }
939
940     Address callAddress = finiRegion->getMemOffset() + bytesSeen;
941
942     RegisterAST thePC = RegisterAST(
943         Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
944
945     Expression::Ptr callTarget = lastCall->getControlFlowTarget();
946     if( !callTarget.get() ) {
947         logLine("failed to find global destructor function\n");
948         return NULL;
949     }
950     callTarget->bind(&thePC, Result(s64, callAddress));
951
952     Result actualTarget = callTarget->eval();
953     if( actualTarget.defined ) {
954         dtorAddress = actualTarget.convert<Address>();
955     }else{
956         logLine("failed to find global destructor function\n");
957         return NULL;
958     }
959
960     if( !dtorAddress || !parse_img()->codeObject()->cs()->isValidAddress(dtorAddress) ) {
961         logLine("invalid address for global destructor function\n");
962         return NULL;
963     }
964
965     // A targ stub should have been created at the address
966     func_instance *ret = NULL;
967     if( (ret = findFuncByEntry(dtorAddress)) == NULL ) {
968         logLine("unable to find global destructor function\n");
969         return NULL;
970     }
971     inst_printf("%s[%d]: set global destructor address to 0x%lx\n", FILE__, __LINE__,
972             dtorAddress);
973
974     return ret;
975 }
976