SymtabAPI::Region::getRegionSize is dangerous and has been REMOVED.
[dyninst.git] / dyninstAPI / src / parse-x86.C
1 /*
2  * Copyright (c) 1996-2011 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 /*
33  * inst-x86.C - x86 dependent functions and code generator
34  */
35
36 #include "common/h/Vector.h"
37 #include "common/h/Dictionary.h"
38 #include "common/h/Vector.h"
39 #include "parse-cfg.h"
40 #include "instPoint.h"
41 #include "mapped_object.h"
42 #include "symtab.h"
43 #include "dyninstAPI/h/BPatch_Set.h"
44 #include "debug.h"
45 #include <deque>
46 #include <set>
47 #include <algorithm>
48 //#include "arch.h"
49
50 #include "instructionAPI/h/Instruction.h"
51 #include "instructionAPI/h/InstructionDecoder.h"
52
53 using namespace Dyninst::ParseAPI;
54
55 bool parse_func::writesFPRs(unsigned level) {
56     
57     using namespace Dyninst::InstructionAPI;
58     // Oh, we should be parsed by now...
59     if (!parsed()) image_->analyzeIfNeeded();
60
61     if (containsFPRWrites_ == unknown) {
62         // Iterate down and find out...
63         // We know if we have callees because we can
64         // check the instPoints; no reason to iterate over.
65         // We also cache callee values here for speed.
66
67         if (level >= 3) {
68             return true; // Arbitrarily decided level 3 iteration.
69         }        
70         Function::edgelist & calls = callEdges();
71         Function::edgelist::iterator cit = calls.begin();
72         for( ; cit != calls.end(); ++cit) {
73             image_edge * ce = static_cast<image_edge*>(*cit);
74             parse_func * ct = static_cast<parse_func*>(
75                 obj()->findFuncByEntry(region(),ce->trg()->start()));
76             if(ct && ct != this) {
77                 if (ct->writesFPRs(level+1)) {
78                     // One of our kids does... if we're top-level, cache it; in 
79                     // any case, return
80                     if (level == 0)
81                         containsFPRWrites_ = used;
82                     return true;
83                 }
84             }
85             else if(!ct){
86                 // Indirect call... oh, yeah. 
87                 if (level == 0)
88                     containsFPRWrites_ = used;
89                 return true;
90             }
91         }
92
93         // No kids contain writes. See if our code does.
94         static RegisterAST::Ptr st0(new RegisterAST(x86::st0));
95         static RegisterAST::Ptr st1(new RegisterAST(x86::st1));
96         static RegisterAST::Ptr st2(new RegisterAST(x86::st2));
97         static RegisterAST::Ptr st3(new RegisterAST(x86::st3));
98         static RegisterAST::Ptr st4(new RegisterAST(x86::st4));
99         static RegisterAST::Ptr st5(new RegisterAST(x86::st5));
100         static RegisterAST::Ptr st6(new RegisterAST(x86::st6));
101         static RegisterAST::Ptr st7(new RegisterAST(x86::st7));
102         static RegisterAST::Ptr xmm0(new RegisterAST(x86::xmm0));
103         static RegisterAST::Ptr xmm1(new RegisterAST(x86::xmm1));
104         static RegisterAST::Ptr xmm2(new RegisterAST(x86::xmm2));
105         static RegisterAST::Ptr xmm3(new RegisterAST(x86::xmm3));
106         static RegisterAST::Ptr xmm4(new RegisterAST(x86::xmm4));
107         static RegisterAST::Ptr xmm5(new RegisterAST(x86::xmm5));
108         static RegisterAST::Ptr xmm6(new RegisterAST(x86::xmm6));
109         static RegisterAST::Ptr xmm7(new RegisterAST(x86::xmm7));
110
111         vector<FuncExtent *>::const_iterator eit = extents().begin();
112         for( ; eit != extents().end(); ++eit) {
113             FuncExtent * fe = *eit;
114         
115             const unsigned char* buf = (const unsigned char*)
116                 isrc()->getPtrToInstruction(fe->start());
117             if(!buf) {
118                 parsing_printf("%s[%d]: failed to get insn ptr at %lx\n",
119                     FILE__, __LINE__,fe->start());
120                 // if the function cannot be parsed, it is only safe to 
121                 // assume that the FPRs are written -- mcnulty
122                 return true; 
123             }
124             InstructionDecoder d(buf,fe->end()-fe->start(),isrc()->getArch());
125             Instruction::Ptr i;
126
127             while(i = d.decode()) {
128                 if(i->isWritten(st0) ||
129                     i->isWritten(st1) ||
130                     i->isWritten(st2) ||
131                     i->isWritten(st3) ||
132                     i->isWritten(st4) ||
133                     i->isWritten(st5) ||
134                     i->isWritten(st6) ||
135                     i->isWritten(st7) ||
136                    i->isWritten(xmm0) ||
137                    i->isWritten(xmm1) ||
138                    i->isWritten(xmm2) ||
139                    i->isWritten(xmm3) ||
140                    i->isWritten(xmm4) ||
141                    i->isWritten(xmm5) ||
142                    i->isWritten(xmm6) ||
143                    i->isWritten(xmm7)
144                   )
145                 {
146                     containsFPRWrites_ = used;
147                     return true;
148                 }
149             }
150         }
151         // No kids do, and we don't. Impressive.
152         containsFPRWrites_ = unused;
153         return false;
154     }
155     else if (containsFPRWrites_ == used) {
156         return true;
157     }
158     else if (containsFPRWrites_ == unused) {
159         return false;
160     }
161
162     fprintf(stderr, "ERROR: function %s, containsFPRWrites_ is %d (illegal value!)\n", 
163             symTabName().c_str(), containsFPRWrites_);
164     
165     assert(0);
166     return false;
167 }
168
169 #if defined(os_linux) || defined(os_freebsd)
170
171 #include "binaryEdit.h"
172 #include "addressSpace.h"
173 #include "function.h"
174 #include "miniTramp.h"
175 #include "baseTramp.h"
176 #include "symtab.h"
177
178 using namespace Dyninst::SymtabAPI;
179
180 /*
181  * Static binary rewriting support
182  *
183  * Some of the following functions replace the standard ctor and dtor handlers
184  * in a binary. Currently, these operations only work with binaries linked with
185  * the GNU toolchain. However, it should be straightforward to extend these
186  * operations to other toolchains.
187  */
188 static const std::string LIBC_CTOR_HANDLER("__do_global_ctors_aux");
189 static const std::string LIBC_DTOR_HANDLER("__do_global_dtors_aux");
190 static const std::string DYNINST_CTOR_HANDLER("DYNINSTglobal_ctors_handler");
191 static const std::string DYNINST_CTOR_LIST("DYNINSTctors_addr");
192 static const std::string DYNINST_DTOR_HANDLER("DYNINSTglobal_dtors_handler");
193 static const std::string DYNINST_DTOR_LIST("DYNINSTdtors_addr");
194 static const std::string SYMTAB_CTOR_LIST_REL("__SYMTABAPI_CTOR_LIST__");
195 static const std::string SYMTAB_DTOR_LIST_REL("__SYMTABAPI_DTOR_LIST__");
196
197 static bool replaceHandler(func_instance *origHandler, func_instance *newHandler, 
198         int_symbol *newList, const std::string &listRelName)
199 {
200     // Add instrumentation to replace the function
201    // TODO: this should be a function replacement!
202    // And why the hell is it in parse-x86.C?
203    origHandler->proc()->replaceFunction(origHandler, newHandler);
204    //origHandler->proc()->relocate();
205     /* PatchAPI stuffs */
206     AddressSpace::patch(origHandler->proc());
207     /* End of PatchAPI stuffs */
208
209     
210     /* create the special relocation for the new list -- search the RT library for
211      * the symbol
212      */
213     Symbol *newListSym = const_cast<Symbol *>(newList->sym());
214     
215     std::vector<Region *> allRegions;
216     if( !newListSym->getSymtab()->getAllRegions(allRegions) ) {
217         return false;
218     }
219
220     bool success = false;
221     std::vector<Region *>::iterator reg_it;
222     for(reg_it = allRegions.begin(); reg_it != allRegions.end(); ++reg_it) {
223         std::vector<relocationEntry> &region_rels = (*reg_it)->getRelocations();
224         vector<relocationEntry>::iterator rel_it;
225         for( rel_it = region_rels.begin(); rel_it != region_rels.end(); ++rel_it) {
226             if( rel_it->getDynSym() == newListSym ) {
227                 relocationEntry *rel = &(*rel_it);
228                 rel->setName(listRelName);
229                 success = true;
230             }
231         }
232     }
233
234     return success;
235 }
236
237 bool BinaryEdit::doStaticBinarySpecialCases() {
238     Symtab *origBinary = mobj->parse_img()->getObject();
239
240     /* Special Case 1: Handling global constructor and destructor Regions
241      *
242      * Replace global ctors function with special ctors function,
243      * and create a special relocation for the ctors list used by the special
244      * ctors function
245      *
246      * Replace global dtors function with special dtors function,
247      * and create a special relocation for the dtors list used by the special
248      * dtors function
249      */
250
251     // First, find all the necessary symbol info.
252     func_instance *globalCtorHandler = mobj->findGlobalConstructorFunc(LIBC_CTOR_HANDLER);
253     if( !globalCtorHandler ) {
254         logLine("failed to find libc constructor handler\n");
255         return false;
256     }
257
258     func_instance *dyninstCtorHandler = findOnlyOneFunction(DYNINST_CTOR_HANDLER);
259     if( !dyninstCtorHandler ) {
260         logLine("failed to find Dyninst constructor handler\n");
261         return false;
262     }
263
264     func_instance *globalDtorHandler = mobj->findGlobalDestructorFunc(LIBC_DTOR_HANDLER);
265     if( !globalDtorHandler ) {
266         logLine("failed to find libc destructor handler\n");
267         return false;
268     }
269
270     func_instance *dyninstDtorHandler = findOnlyOneFunction(DYNINST_DTOR_HANDLER);
271     if( !dyninstDtorHandler ) {
272         logLine("failed to find Dyninst destructor handler\n");
273         return false;
274     }
275
276     int_symbol ctorsListInt;
277     int_symbol dtorsListInt;
278     bool ctorFound = false, dtorFound = false; 
279     std::vector<BinaryEdit *>::iterator rtlib_it;
280     for(rtlib_it = rtlib.begin(); rtlib_it != rtlib.end(); ++rtlib_it) {
281         if( (*rtlib_it)->getSymbolInfo(DYNINST_CTOR_LIST, ctorsListInt) ) {
282             ctorFound = true;
283             if( dtorFound ) break;
284         }
285
286         if( (*rtlib_it)->getSymbolInfo(DYNINST_DTOR_LIST, dtorsListInt) ) {
287             dtorFound = true;
288             if( ctorFound ) break;
289         }
290     }
291
292     if( !ctorFound ) {
293          logLine("failed to find ctors list symbol\n");
294          return false;
295     }
296
297     if( !dtorFound ) {
298         logLine("failed to find dtors list symbol\n");
299         return false;
300     }
301
302     /*
303      * Replace the libc ctor and dtor handlers with our special handlers
304      */
305     if( !replaceHandler(globalCtorHandler, dyninstCtorHandler,
306                 &ctorsListInt, SYMTAB_CTOR_LIST_REL) ) {
307         logLine("Failed to replace libc ctor handler with special handler");
308         return false;
309     }else{
310         inst_printf("%s[%d]: replaced ctor function %s with %s\n",
311                 FILE__, __LINE__, LIBC_CTOR_HANDLER.c_str(),
312                 DYNINST_CTOR_HANDLER.c_str());
313     }
314
315     if( !replaceHandler(globalDtorHandler, dyninstDtorHandler,
316                 &dtorsListInt, SYMTAB_DTOR_LIST_REL) ) {
317         logLine("Failed to replace libc dtor handler with special handler");
318         return false;
319     }else{
320         inst_printf("%s[%d]: replaced dtor function %s with %s\n",
321                 FILE__, __LINE__, LIBC_DTOR_HANDLER.c_str(),
322                 DYNINST_DTOR_HANDLER.c_str());
323     }
324
325     /*
326      * Special Case 2: Issue a warning if attempting to link pthreads into a binary
327      * that originally did not support it or into a binary that is stripped. This
328      * scenario is not supported with the initial release of the binary rewriter for
329      * static binaries.
330      *
331      * The other side of the coin, if working with a binary that does have pthreads
332      * support, pthreads needs to be loaded.
333      */
334     bool isMTCapable = isMultiThreadCapable();
335     bool foundPthreads = false;
336
337     vector<Archive *> libs;
338     vector<Archive *>::iterator libIter;
339     if( origBinary->getLinkingResources(libs) ) {
340         for(libIter = libs.begin(); libIter != libs.end(); ++libIter) {
341             if( (*libIter)->name().find("libpthread") != std::string::npos ||
342                 (*libIter)->name().find("libthr") != std::string::npos ) 
343             {
344                 foundPthreads = true;
345                 break;
346             }
347         }
348     }
349
350     if( foundPthreads && (!isMTCapable || origBinary->isStripped()) ) {
351         fprintf(stderr,
352             "\nWARNING: the pthreads library has been loaded and\n"
353             "the original binary is not multithread-capable or\n"
354             "it is stripped. Currently, the combination of these two\n"
355             "scenarios is unsupported and unexpected behavior may occur.\n");
356     }else if( !foundPthreads && isMTCapable ) {
357         fprintf(stderr,
358             "\nWARNING: the pthreads library has not been loaded and\n"
359             "the original binary is multithread-capable. Unexpected\n"
360             "behavior may occur because some pthreads routines are\n"
361             "unavailable in the original binary\n");
362     }
363
364     /* 
365      * Special Case 3:
366      * The RT library has some dependencies -- Symtab always needs to know
367      * about these dependencies. So if the dependencies haven't already been
368      * loaded, load them.
369      */
370     bool loadLibc = true;
371
372     for(libIter = libs.begin(); libIter != libs.end(); ++libIter) {
373         if( (*libIter)->name().find("libc.a") != std::string::npos ) {
374             loadLibc = false;
375         }
376     }
377
378     if( loadLibc ) {
379        std::map<std::string, BinaryEdit *> res;
380        openResolvedLibraryName("libc.a", res);
381        std::map<std::string, BinaryEdit *>::iterator bedit_it;
382        for(bedit_it = res.begin(); bedit_it != res.end(); ++bedit_it) {
383           if( bedit_it->second == NULL ) {
384              logLine("Failed to load DyninstAPI_RT library dependency (libc.a)");
385              return false;
386           }
387        }
388     }
389     
390     return true;
391 }
392
393 func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorHandler) {
394     using namespace Dyninst::InstructionAPI;
395
396     const pdvector<func_instance *> *funcs = findFuncVectorByMangled(ctorHandler);
397     if( funcs != NULL ) {
398         return funcs->at(0);
399     }
400
401     /* If the symbol isn't found, try looking for it in a call instruction in
402      * the .init section
403      *
404      * On Linux, the instruction sequence is:
405      * ...
406      * some instructions
407      * ...
408      * call call_gmon_start
409      * call frame_dummy
410      * call ctor_handler
411      *
412      * On FreeBSD, the instruction sequence is:
413      * ...
414      * some instructions
415      * ...
416      * call frame_dummy
417      * call ctor_handler
418      */
419     Symtab *linkedFile = parse_img()->getObject();
420     Region *initRegion = NULL;
421     if( !linkedFile->findRegion(initRegion, ".init") ) {
422         vector<Dyninst::SymtabAPI::Function *> symFuncs;
423         if( linkedFile->findFunctionsByName(symFuncs, "_init") ) {
424             initRegion = symFuncs[0]->getRegion();
425         }else{
426             logLine("failed to locate .init Region or _init function\n");
427             return NULL;
428         }
429     }
430
431     if( initRegion == NULL ) {
432         logLine("failed to locate .init Region or _init function\n");
433         return NULL;
434     }
435
436     // Search for last of a fixed number of calls
437 #if defined(os_freebsd)
438     const unsigned CTOR_NUM_CALLS = 2;
439 #else
440     const unsigned CTOR_NUM_CALLS = 3;
441 #endif
442
443     Address ctorAddress = 0;
444     unsigned bytesSeen = 0;
445     unsigned numCalls = 0;
446     const unsigned char *p = reinterpret_cast<const unsigned char *>(initRegion->getPtrToRawData());
447
448     InstructionDecoder decoder(p, initRegion->getDiskSize(),
449         parse_img()->codeObject()->cs()->getArch()); 
450
451     Instruction::Ptr curInsn = decoder.decode();
452     while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() &&
453           bytesSeen < initRegion->getDiskSize()) 
454     {
455         InsnCategory category = curInsn->getCategory();
456         if( category == c_CallInsn ) {
457             numCalls++;
458         }
459         if( numCalls < CTOR_NUM_CALLS ) {
460             bytesSeen += curInsn->size();
461             curInsn = decoder.decode();
462         }
463     }
464
465     if( numCalls != CTOR_NUM_CALLS ) {
466         logLine("heuristic for finding global constructor function failed\n");
467         return NULL;
468     }
469
470     Address callAddress = initRegion->getRegionAddr() + bytesSeen;
471
472     RegisterAST thePC = RegisterAST(
473         Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
474
475     Expression::Ptr callTarget = curInsn->getControlFlowTarget();
476     if( !callTarget.get() ) {
477         logLine("failed to find global constructor function\n");
478         return NULL;
479     }
480     callTarget->bind(&thePC, Result(s64, callAddress));
481
482     Result actualTarget = callTarget->eval();
483     if( actualTarget.defined ) {
484         ctorAddress = actualTarget.convert<Address>();
485     }else{
486         logLine("failed to find global constructor function\n");
487         return NULL;
488     }
489
490     if( !ctorAddress || !parse_img()->codeObject()->cs()->isValidAddress(ctorAddress) ) {
491         logLine("invalid address for global constructor function\n");
492         return NULL;
493     }
494
495     func_instance *ret;
496     if( (ret = findFuncByEntry(ctorAddress)) == NULL ) {
497         logLine("unable to create representation for global constructor function\n");
498         return NULL;
499     }
500
501     inst_printf("%s[%d]: set global constructor address to 0x%lx\n", FILE__, __LINE__,
502             ctorAddress);
503
504     return ret;
505 }
506
507 func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHandler) {
508     using namespace Dyninst::InstructionAPI;
509
510     const pdvector<func_instance *> *funcs = findFuncVectorByMangled(dtorHandler);
511     if( funcs != NULL ) {
512         return funcs->at(0);
513     }
514
515     /*
516      * If the symbol isn't found, try looking for it in a call in the
517      * .fini section. It is the last call in .fini.
518      *
519      * The pattern is:
520      *
521      * _fini:
522      *
523      * ... some code ...
524      *
525      * call dtor_handler
526      *
527      * ... prologue ...
528      */
529     Symtab *linkedFile = parse_img()->getObject();
530     Region *finiRegion = NULL;
531     if( !linkedFile->findRegion(finiRegion, ".fini") ) {
532         vector<Dyninst::SymtabAPI::Function *> symFuncs;
533         if( linkedFile->findFunctionsByName(symFuncs, "_fini") ) {
534             finiRegion = symFuncs[0]->getRegion();
535         }else{
536             logLine("failed to locate .fini Region or _fini function\n");
537             return NULL;
538         }
539     }
540
541     if( finiRegion == NULL ) {
542         logLine("failed to locate .fini Region or _fini function\n");
543         return NULL;
544     }
545
546     // Search for last call in the function
547     Address dtorAddress = 0;
548     unsigned bytesSeen = 0;
549     const unsigned char *p = reinterpret_cast<const unsigned char *>(finiRegion->getPtrToRawData());
550
551     InstructionDecoder decoder(p, finiRegion->getDiskSize(),
552         parse_img()->codeObject()->cs()->getArch());
553
554     Instruction::Ptr lastCall;
555     Instruction::Ptr curInsn = decoder.decode();
556
557     while(curInsn && curInsn->isValid() &&
558           bytesSeen < finiRegion->getDiskSize()) 
559     {
560         InsnCategory category = curInsn->getCategory();
561         if( category == c_CallInsn ) {
562             lastCall = curInsn;
563             break;
564         }
565
566         bytesSeen += curInsn->size();
567         curInsn = decoder.decode();
568     }
569
570     if( !lastCall.get() || !lastCall->isValid() ) {
571         logLine("heuristic for finding global destructor function failed\n");
572         return NULL;
573     }
574
575     Address callAddress = finiRegion->getRegionAddr() + bytesSeen;
576
577     RegisterAST thePC = RegisterAST(
578         Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
579
580     Expression::Ptr callTarget = lastCall->getControlFlowTarget();
581     if( !callTarget.get() ) {
582         logLine("failed to find global destructor function\n");
583         return NULL;
584     }
585     callTarget->bind(&thePC, Result(s64, callAddress));
586
587     Result actualTarget = callTarget->eval();
588     if( actualTarget.defined ) {
589         dtorAddress = actualTarget.convert<Address>();
590     }else{
591         logLine("failed to find global destructor function\n");
592         return NULL;
593     }
594
595     if( !dtorAddress || !parse_img()->codeObject()->cs()->isValidAddress(dtorAddress) ) {
596         logLine("invalid address for global destructor function\n");
597         return NULL;
598     }
599
600     // A targ stub should have been created at the address
601     func_instance *ret = NULL;
602     if( (ret = findFuncByEntry(dtorAddress)) == NULL ) {
603         logLine("unable to find global destructor function\n");
604         return NULL;
605     }
606     inst_printf("%s[%d]: set global destructor address to 0x%lx\n", FILE__, __LINE__,
607             dtorAddress);
608
609     return ret;
610 }
611
612 #endif