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