2 * See the dyninst/COPYRIGHT file for copyright information.
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.
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.
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.
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.
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
32 * inst-x86.C - x86 dependent functions and code generator
35 #include "common/h/Vector.h"
36 #include "common/h/Dictionary.h"
37 #include "common/h/Vector.h"
38 #include "parse-cfg.h"
39 #include "instPoint.h"
40 #include "mapped_object.h"
42 #include "dyninstAPI/h/BPatch_Set.h"
49 #include "instructionAPI/h/Instruction.h"
50 #include "instructionAPI/h/InstructionDecoder.h"
52 using namespace Dyninst::ParseAPI;
54 bool parse_func::writesFPRs(unsigned level) {
56 using namespace Dyninst::InstructionAPI;
57 // Oh, we should be parsed by now...
58 if (!parsed()) image_->analyzeIfNeeded();
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.
67 return true; // Arbitrarily decided level 3 iteration.
69 const Function::edgelist & calls = callEdges();
70 Function::edgelist::const_iterator cit = calls.begin();
71 for( ; cit != calls.end(); ++cit) {
72 image_edge * ce = static_cast<image_edge*>(*cit);
73 parse_func * ct = static_cast<parse_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
80 containsFPRWrites_ = used;
85 // Indirect call... oh, yeah.
87 containsFPRWrites_ = used;
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));
110 vector<FuncExtent *>::const_iterator eit = extents().begin();
111 for( ; eit != extents().end(); ++eit) {
112 FuncExtent * fe = *eit;
114 const unsigned char* buf = (const unsigned char*)
115 isrc()->getPtrToInstruction(fe->start());
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
123 InstructionDecoder d(buf,fe->end()-fe->start(),isrc()->getArch());
126 while(i = d.decode()) {
127 if(i->isWritten(st0) ||
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) ||
145 containsFPRWrites_ = used;
150 // No kids do, and we don't. Impressive.
151 containsFPRWrites_ = unused;
154 else if (containsFPRWrites_ == used) {
157 else if (containsFPRWrites_ == unused) {
161 fprintf(stderr, "ERROR: function %s, containsFPRWrites_ is %d (illegal value!)\n",
162 symTabName().c_str(), containsFPRWrites_);
168 #if defined(os_linux) || defined(os_freebsd)
170 #include "binaryEdit.h"
171 #include "addressSpace.h"
172 #include "function.h"
173 #include "baseTramp.h"
176 using namespace Dyninst::SymtabAPI;
179 * Static binary rewriting support
181 * Some of the following functions replace the standard ctor and dtor handlers
182 * in a binary. Currently, these operations only work with binaries linked with
183 * the GNU toolchain. However, it should be straightforward to extend these
184 * operations to other toolchains.
186 static const std::string LIBC_CTOR_HANDLER("__do_global_ctors_aux");
187 static const std::string LIBC_DTOR_HANDLER("__do_global_dtors_aux");
188 static const std::string DYNINST_CTOR_HANDLER("DYNINSTglobal_ctors_handler");
189 static const std::string DYNINST_CTOR_LIST("DYNINSTctors_addr");
190 static const std::string DYNINST_DTOR_HANDLER("DYNINSTglobal_dtors_handler");
191 static const std::string DYNINST_DTOR_LIST("DYNINSTdtors_addr");
192 static const std::string SYMTAB_CTOR_LIST_REL("__SYMTABAPI_CTOR_LIST__");
193 static const std::string SYMTAB_DTOR_LIST_REL("__SYMTABAPI_DTOR_LIST__");
195 static bool replaceHandler(func_instance *origHandler, func_instance *newHandler,
196 int_symbol *newList, const std::string &listRelName)
198 // Add instrumentation to replace the function
199 // TODO: this should be a function replacement!
200 // And why the hell is it in parse-x86.C?
201 origHandler->proc()->replaceFunction(origHandler, newHandler);
202 //origHandler->proc()->relocate();
203 /* PatchAPI stuffs */
204 AddressSpace::patch(origHandler->proc());
205 /* End of PatchAPI stuffs */
208 /* create the special relocation for the new list -- search the RT library for
211 Symbol *newListSym = const_cast<Symbol *>(newList->sym());
213 std::vector<Region *> allRegions;
214 if( !newListSym->getSymtab()->getAllRegions(allRegions) ) {
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> ®ion_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);
235 bool BinaryEdit::doStaticBinarySpecialCases() {
236 Symtab *origBinary = mobj->parse_img()->getObject();
238 /* Special Case 1: Handling global constructor and destructor Regions
240 * Replace global ctors function with special ctors function,
241 * and create a special relocation for the ctors list used by the special
244 * Replace global dtors function with special dtors function,
245 * and create a special relocation for the dtors list used by the special
249 // First, find all the necessary symbol info.
250 func_instance *globalCtorHandler = mobj->findGlobalConstructorFunc(LIBC_CTOR_HANDLER);
251 if( !globalCtorHandler ) {
252 logLine("failed to find libc constructor handler\n");
256 func_instance *dyninstCtorHandler = findOnlyOneFunction(DYNINST_CTOR_HANDLER);
257 if( !dyninstCtorHandler ) {
258 logLine("failed to find Dyninst constructor handler\n");
262 func_instance *globalDtorHandler = mobj->findGlobalDestructorFunc(LIBC_DTOR_HANDLER);
263 if( !globalDtorHandler ) {
264 logLine("failed to find libc destructor handler\n");
268 func_instance *dyninstDtorHandler = findOnlyOneFunction(DYNINST_DTOR_HANDLER);
269 if( !dyninstDtorHandler ) {
270 logLine("failed to find Dyninst destructor handler\n");
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) ) {
281 if( dtorFound ) break;
284 if( (*rtlib_it)->getSymbolInfo(DYNINST_DTOR_LIST, dtorsListInt) ) {
286 if( ctorFound ) break;
291 logLine("failed to find ctors list symbol\n");
296 logLine("failed to find dtors list symbol\n");
301 * Replace the libc ctor and dtor handlers with our special handlers
303 if( !replaceHandler(globalCtorHandler, dyninstCtorHandler,
304 &ctorsListInt, SYMTAB_CTOR_LIST_REL) ) {
305 logLine("Failed to replace libc ctor handler with special handler");
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());
313 if( !replaceHandler(globalDtorHandler, dyninstDtorHandler,
314 &dtorsListInt, SYMTAB_DTOR_LIST_REL) ) {
315 logLine("Failed to replace libc dtor handler with special handler");
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());
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
329 * The other side of the coin, if working with a binary that does have pthreads
330 * support, pthreads needs to be loaded.
332 bool isMTCapable = isMultiThreadCapable();
333 bool foundPthreads = false;
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 )
342 foundPthreads = true;
348 if( foundPthreads && (!isMTCapable || origBinary->isStripped()) ) {
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 ) {
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");
364 * The RT library has some dependencies -- Symtab always needs to know
365 * about these dependencies. So if the dependencies haven't already been
368 bool loadLibc = true;
370 for(libIter = libs.begin(); libIter != libs.end(); ++libIter) {
371 if( (*libIter)->name().find("libc.a") != std::string::npos ) {
377 std::map<std::string, BinaryEdit *> res;
378 openResolvedLibraryName("libc.a", res);
379 std::map<std::string, BinaryEdit *>::iterator bedit_it;
380 for(bedit_it = res.begin(); bedit_it != res.end(); ++bedit_it) {
381 if( bedit_it->second == NULL ) {
382 logLine("Failed to load DyninstAPI_RT library dependency (libc.a)");
391 func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorHandler) {
392 using namespace Dyninst::InstructionAPI;
394 const pdvector<func_instance *> *funcs = findFuncVectorByMangled(ctorHandler);
395 if( funcs != NULL ) {
399 /* If the symbol isn't found, try looking for it in a call instruction in
402 * On Linux, the instruction sequence is:
406 * call call_gmon_start
410 * On FreeBSD, the instruction sequence is:
417 Symtab *linkedFile = parse_img()->getObject();
418 Region *initRegion = NULL;
419 if( !linkedFile->findRegion(initRegion, ".init") ) {
420 vector<Dyninst::SymtabAPI::Function *> symFuncs;
421 if( linkedFile->findFunctionsByName(symFuncs, "_init") ) {
422 initRegion = symFuncs[0]->getRegion();
424 logLine("failed to locate .init Region or _init function\n");
429 if( initRegion == NULL ) {
430 logLine("failed to locate .init Region or _init function\n");
434 // Search for last of a fixed number of calls
435 #if defined(os_freebsd)
436 const unsigned CTOR_NUM_CALLS = 2;
438 const unsigned CTOR_NUM_CALLS = 3;
441 Address ctorAddress = 0;
442 unsigned bytesSeen = 0;
443 unsigned numCalls = 0;
444 const unsigned char *p = reinterpret_cast<const unsigned char *>(initRegion->getPtrToRawData());
446 InstructionDecoder decoder(p, initRegion->getDiskSize(),
447 parse_img()->codeObject()->cs()->getArch());
449 Instruction::Ptr curInsn = decoder.decode();
450 while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() &&
451 bytesSeen < initRegion->getDiskSize())
453 InsnCategory category = curInsn->getCategory();
454 if( category == c_CallInsn ) {
457 if( numCalls < CTOR_NUM_CALLS ) {
458 bytesSeen += curInsn->size();
459 curInsn = decoder.decode();
463 if( numCalls != CTOR_NUM_CALLS ) {
464 logLine("heuristic for finding global constructor function failed\n");
468 Address callAddress = initRegion->getMemOffset() + bytesSeen;
470 RegisterAST thePC = RegisterAST(
471 Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
473 Expression::Ptr callTarget = curInsn->getControlFlowTarget();
474 if( !callTarget.get() ) {
475 logLine("failed to find global constructor function\n");
478 callTarget->bind(&thePC, Result(s64, callAddress));
480 Result actualTarget = callTarget->eval();
481 if( actualTarget.defined ) {
482 ctorAddress = actualTarget.convert<Address>();
484 logLine("failed to find global constructor function\n");
488 if( !ctorAddress || !parse_img()->codeObject()->cs()->isValidAddress(ctorAddress) ) {
489 logLine("invalid address for global constructor function\n");
494 if( (ret = findFuncByEntry(ctorAddress)) == NULL ) {
495 logLine("unable to create representation for global constructor function\n");
499 inst_printf("%s[%d]: set global constructor address to 0x%lx\n", FILE__, __LINE__,
505 func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHandler) {
506 using namespace Dyninst::InstructionAPI;
508 const pdvector<func_instance *> *funcs = findFuncVectorByMangled(dtorHandler);
509 if( funcs != NULL ) {
514 * If the symbol isn't found, try looking for it in a call in the
515 * .fini section. It is the last call in .fini.
527 Symtab *linkedFile = parse_img()->getObject();
528 Region *finiRegion = NULL;
529 if( !linkedFile->findRegion(finiRegion, ".fini") ) {
530 vector<Dyninst::SymtabAPI::Function *> symFuncs;
531 if( linkedFile->findFunctionsByName(symFuncs, "_fini") ) {
532 finiRegion = symFuncs[0]->getRegion();
534 logLine("failed to locate .fini Region or _fini function\n");
539 if( finiRegion == NULL ) {
540 logLine("failed to locate .fini Region or _fini function\n");
544 // Search for last call in the function
545 Address dtorAddress = 0;
546 unsigned bytesSeen = 0;
547 const unsigned char *p = reinterpret_cast<const unsigned char *>(finiRegion->getPtrToRawData());
549 InstructionDecoder decoder(p, finiRegion->getDiskSize(),
550 parse_img()->codeObject()->cs()->getArch());
552 Instruction::Ptr lastCall;
553 Instruction::Ptr curInsn = decoder.decode();
555 while(curInsn && curInsn->isValid() &&
556 bytesSeen < finiRegion->getDiskSize())
558 InsnCategory category = curInsn->getCategory();
559 if( category == c_CallInsn ) {
564 bytesSeen += curInsn->size();
565 curInsn = decoder.decode();
568 if( !lastCall.get() || !lastCall->isValid() ) {
569 logLine("heuristic for finding global destructor function failed\n");
573 Address callAddress = finiRegion->getMemOffset() + bytesSeen;
575 RegisterAST thePC = RegisterAST(
576 Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch()));
578 Expression::Ptr callTarget = lastCall->getControlFlowTarget();
579 if( !callTarget.get() ) {
580 logLine("failed to find global destructor function\n");
583 callTarget->bind(&thePC, Result(s64, callAddress));
585 Result actualTarget = callTarget->eval();
586 if( actualTarget.defined ) {
587 dtorAddress = actualTarget.convert<Address>();
589 logLine("failed to find global destructor function\n");
593 if( !dtorAddress || !parse_img()->codeObject()->cs()->isValidAddress(dtorAddress) ) {
594 logLine("invalid address for global destructor function\n");
598 // A targ stub should have been created at the address
599 func_instance *ret = NULL;
600 if( (ret = findFuncByEntry(dtorAddress)) == NULL ) {
601 logLine("unable to find global destructor function\n");
604 inst_printf("%s[%d]: set global destructor address to 0x%lx\n", FILE__, __LINE__,