Ejemplo n.º 1
0
AbsRegion AbsRegionConverter::convert(RegisterAST::Ptr reg) {
  // FIXME:
  // Upcast register so we can be sure to match things later
  AbsRegion tmp = AbsRegion(Absloc(reg->getID().getBaseRegister()));

  //std::cerr << "ARC::convert from " << reg->format() << " to "
  //    << tmp.format() << std::endl;
  return tmp;
}
Ejemplo n.º 2
0
static Address ThunkAdjustment(Address afterThunk, MachRegister reg, ParseAPI::Block *b) {
    // After the call to thunk, there is usually
    // an add insturction like ADD ebx, OFFSET to adjust
    // the value coming out of thunk.
   
    const unsigned char* buf = (const unsigned char*) (b->obj()->cs()->getPtrToInstruction(afterThunk));
    InstructionDecoder dec(buf, b->end() - b->start(), b->obj()->cs()->getArch());
    Instruction::Ptr nextInsn = dec.decode();
    // It has to be an add
    if (nextInsn->getOperation().getID() != e_add) return 0;
    vector<Operand> operands;
    nextInsn->getOperands(operands);
    RegisterAST::Ptr regAST = boost::dynamic_pointer_cast<RegisterAST>(operands[0].getValue());
    // The first operand should be a register
    if (regAST == 0) return 0;
    if (regAST->getID() != reg) return 0;
    Result res = operands[1].getValue()->eval();
    // A not defined result means that
    // the second operand is not an immediate
    if (!res.defined) return 0;
    return res.convert<Address>();
}
Ejemplo n.º 3
0
// This should only be called on a known indirect branch...
bool IA_powerDetails::parseJumpTable(Block* currBlk,
				     std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges)
{

  Address initialAddress = currentBlock->current;
  toc_reg.reset(new RegisterAST(ppc32::r2));

  TOC_address = currentBlock->_obj->cs()->getTOC();
  toc_visitor.reset(new detail::TOCandOffsetExtractor(TOC_address));
  toc_visitor->toc_reg = toc_reg;
    
  // If there are no prior instructions then we can't be looking at a
  // jump through a jump table.
  if(currentBlock->allInsns.size() < 2) {
    parsing_printf("%s[%d]: allInsns.size() == %d, ret false", FILE__, __LINE__, currentBlock->allInsns.size());
    return false;
  }


  // Check if the previous instruction is a move to CTR or LR;
  // if it is, then this is the pattern we're familiar with.  The
  // register being moved into CTR or LR has the address to jump to.
  patternIter = currentBlock->curInsnIter;
  patternIter--;
  RegisterAST::Ptr jumpAddrReg;
  static RegisterAST::Ptr linkReg(new RegisterAST(ppc32::lr));
  static RegisterAST::Ptr countReg(new RegisterAST(ppc32::ctr));
  std::set<RegisterAST::Ptr> regs;
  if(patternIter->second->getOperation().getID() == power_op_mtspr &&
     (patternIter->second->isWritten(linkReg) ||
      patternIter->second->isWritten(countReg)))
    {
      regs.clear();
      patternIter->second->getReadSet(regs);
      if(regs.size() != 1) {
	parsing_printf("expected mtspr to read 1 register, insn is %s\n", patternIter->second->format().c_str());
	return false;
      }
      jumpAddrReg = *(regs.begin());
      parsing_printf("%s[%d]: JUMPREG %s mtspr at prev insn %s \n", FILE__, __LINE__, jumpAddrReg->format().c_str(), patternIter->second->format().c_str());
      dfgregs.insert(jumpAddrReg->getID());
    }
  else
    {
      parsing_printf("%s[%d]: couldn't find mtspr at prev insn %s, ret false", FILE__, __LINE__,
		     patternIter->second->format().c_str());
      return false;
    }
  assert(jumpAddrReg);
  // In the pattern we've seen, if the instruction previous to this is
  // an add with a result that ends up being used as the jump address,
  // then we're adding a relative value we got from the table to a base
  // address to get the jump address; in other words, the contents of
  // the jump table are relative.
  tableIsRelative = false;
  if(patternIter != currentBlock->allInsns.begin())
    {
      patternIter--;
      if(patternIter->second->getOperation().getID() == power_op_add &&
	 patternIter->second->isWritten(*(regs.begin())))
        {
	  tableIsRelative = true;
        }
    }
  parsing_printf(" TableIsRelative %d\n", tableIsRelative);

  patternIter = currentBlock->curInsnIter;
    
  jumpStartAddress = 0;
  adjustEntry = 0;
  tableStartAddress = 0;
  adjustTableStartAddress = 0;
  foundAdjustEntry = false;
    
  parsing_printf("\t TOC_address 0x%lx\n", TOC_address);
  if(!TOC_address)
    {
      // Find addi-addis instructions to determine the jump table start address.
      // These instructions can be anywhere in the function before the 
      // indirect jump.Hence parse through the current block and previous block
      // till we reach the function entry.
      Block* worklistBlock = currBlk;
      std::set <Block*> visited;
      std::deque<Block*> worklist;
      worklist.insert(worklist.begin(), worklistBlock);
      visited.insert(worklistBlock);
      Intraproc epred;
      parsing_printf("Looking for table start address over blocks to function entry\n");
      while(!worklist.empty())
        {
	  worklistBlock= worklist.front();
	  worklist.pop_front();
	  parsing_printf("\tAddress low 0x%lx high 0x%lx current block 0x%lx low 0x%lx high 0x%lx \n", worklistBlock->low(), worklistBlock->high(), currentBlock->current, currBlk->low(), currBlk->high());
	  Address blockStart = worklistBlock->start();
	  const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
	  parsing_printf(" Block start 0x%lx \n", blockStart);
	  InstructionDecoder dec(b, worklistBlock->size(), currentBlock->_isrc->getArch());
	  IA_IAPI IABlock(dec, blockStart, currentBlock->_obj, currentBlock->_cr, currentBlock->_isrc, worklistBlock);

	  while(IABlock.getInstruction() && !IABlock.hasCFT()) {
	    IABlock.advance();
	  }

	  patternIter = IABlock.curInsnIter;
	  findTableAddrNoTOC(&IABlock);
	  if(!jumpStartAddress)
	    {
	      jumpStartAddress = tableStartAddress;
	    }
	  if (tableStartAddress != 0) {
	    jumpStartAddress = tableStartAddress;
	    parsing_printf("\t\tjumpStartAddress 0x%lx \n", jumpStartAddress);
	    break;
	  }
	  std::for_each(boost::make_filter_iterator(epred, worklistBlock->sources().begin(), worklistBlock->sources().end()),
			boost::make_filter_iterator(epred, worklistBlock->sources().end(), worklistBlock->sources().end()),
			boost::bind(detail_ppc::processPredecessor, _1, boost::ref(visited), boost::ref(worklist)));

        }

    }
  else if (tableIsRelative) {
    if(!parseRelativeTableIdiom())
      {
	return false;
      }
  } else {
    parsing_printf("\t Table is not relative and we know the TOC is 0x%lx, searching for table base\n",
		   TOC_address);
    foundAdjustEntry = false;
  
    scanForAdjustOrBase(patternIter, currentBlock->allInsns.begin(), jumpAddrReg);

    if (!tableStartAddress) {
      // Keep looking in the immediate predecessor - XLC
      for (Block::edgelist::const_iterator e_iter = currBlk->sources().begin(); 
	   e_iter != currBlk->sources().end(); ++e_iter) {
	Address blockStart = (*e_iter)->src()->start();
	const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
	InstructionDecoder dec(b, (*e_iter)->src()->size(), currentBlock->_isrc->getArch());
	IA_IAPI IABlock(dec, blockStart, currentBlock->_obj, currentBlock->_cr, currentBlock->_isrc, (*e_iter)->src());
	
	// Cache instructions
	while(IABlock.getInstruction() && !IABlock.hasCFT()) {
	  IABlock.advance();
	}

	IA_IAPI::allInsns_t::const_iterator localIter = IABlock.curInsnIter;
	findTableBase(localIter, IABlock.allInsns.begin());
      }
    }	  
  }
    
  const Block::edgelist & sourceEdges = currBlk->sources();
  if(sourceEdges.size() != 1 || (*sourceEdges.begin())->type() == CALL) {
    parsing_printf("%s[%d]: jump table not properly guarded, ret false\n", FILE__, __LINE__);
    return false;
  }


    
  // We could also set this = jumpStartAddress...
  if (tableStartAddress == 0)  {
    parsing_printf("%s[%d]: couldn't find table start addr, ret false\n", FILE__, __LINE__);
    return false;
        
  }
    
  parsing_printf("%s[%d]: table start addr is 0x%x\n", FILE__, __LINE__, tableStartAddress);
  int maxSwitch = 0;
  
  Block* sourceBlock = (*sourceEdges.begin())->src();
  Address blockStart = sourceBlock->start();
  const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
  InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch());
  IA_IAPI prevBlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc, sourceBlock);
  while(!prevBlock.hasCFT() && prevBlock.getInstruction()) {
    prevBlock.advance();
  }

  parsing_printf("%s[%d]: checking for max switch...\n", FILE__, __LINE__);
  bool foundBranch = false;
  IA_IAPI::allInsns_t::reverse_iterator iter;
  for(iter = prevBlock.allInsns.rbegin(); iter != prevBlock.allInsns.rend(); iter++)

    {
      parsing_printf("\t\tchecking insn 0x%x: %s for cond branch + compare\n", iter->first,
		     iter->second->format().c_str());
      if(iter->second->getOperation().getID() == power_op_bc) // make this a true cond. branch check
        {
	  foundBranch = true;
	} else if(foundBranch && 
		  (iter->second->getOperation().getID() == power_op_cmpi ||
                   iter->second->getOperation().getID() == power_op_cmpli))
        {
	  maxSwitch = iter->second->getOperand(2).getValue()->eval().convert<int>() + 1;
	  break;
                
        }
    } 

  parsing_printf("%s[%d]: After checking: max switch %d\n", FILE__, __LINE__, maxSwitch);
  if(!maxSwitch){
    return false;
  }

  Address jumpStart = 0;
  Address tableStart = 0;
  bool is64 = (currentBlock->_isrc->getAddressWidth() == 8);
  std::vector<std::pair< Address, EdgeTypeEnum> > edges;

  if(TOC_address)
    {
      if (tableIsRelative) {
	void *jumpStartPtr = currentBlock->_isrc->getPtrToData(jumpStartAddress);
	parsing_printf("%s[%d]: jumpStartPtr (0x%lx) = %p\n", FILE__, __LINE__, jumpStartAddress, jumpStartPtr);
	if (jumpStartPtr)
	  jumpStart = (is64
		       ? *((Address  *)jumpStartPtr)
		       : *((uint32_t *)jumpStartPtr));
	parsing_printf("%s[%d]: jumpStart 0x%lx, initialAddr 0x%lx\n",
		       FILE__, __LINE__, jumpStart, initialAddress);
	if (jumpStartPtr == NULL) {
	  return false;
	}
      }
      void *tableStartPtr = currentBlock->_isrc->getPtrToData(tableStartAddress);
      parsing_printf("%s[%d]: tableStartPtr (0x%lx) = %p\n", FILE__, __LINE__, tableStartAddress, tableStartPtr);
      tableStart = *((Address *)tableStartPtr);
      if (tableStartPtr)
	tableStart = (is64
		      ? *((Address  *)tableStartPtr)
		      : *((uint32_t *)tableStartPtr));
      else {
	return false;
      }
      parsing_printf("\t... tableStart 0x%lx\n", tableStart);

      bool tableData = false;
      for(int i=0;i<maxSwitch;i++){
	Address tableEntry = adjustEntry + tableStart + (i * 4 /*instruction::size()*/);
	parsing_printf("\t\tTable entry at 0x%lx\n", tableEntry);
	if (currentBlock->_isrc->isValidAddress(tableEntry)) {
	  int jumpOffset;
	  if (tableData) {
	    jumpOffset = *((int *)currentBlock->_isrc->getPtrToData(tableEntry));
	  }
	  else {
	    jumpOffset = *((int *)currentBlock->_isrc->getPtrToInstruction(tableEntry));
	  }

	  parsing_printf("\t\t\tjumpOffset 0x%lx\n", jumpOffset);
	  Address res = (Address)(jumpStart + jumpOffset);

	  if (currentBlock->_isrc->isCode(res)) {
	    edges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT));
	    parsing_printf("\t\t\tEntry of 0x%lx\n", (Address)(jumpStart + jumpOffset));
	  }
	}
	else {
	  parsing_printf("\t\tAddress not valid!\n");
	}
      }
    }
  // No TOC, so we're on Power32 Linux.  Do the ELF thing.
  else
    {
      jumpStart = jumpStartAddress;
      tableStart = tableStartAddress;
      parsing_printf(" jumpStartaddress 0x%lx tableStartAddress 0x%lx \n", jumpStartAddress, tableStartAddress);
      if(toc_visitor->toc_contents)
        {
	  void* tmp = NULL;
	  if(currentBlock->_isrc->isValidAddress(jumpStartAddress))
            {
	      tmp = currentBlock->_isrc->getPtrToData(jumpStartAddress);
	      if(!tmp)
                {
		  tmp = currentBlock->_isrc->getPtrToInstruction(jumpStartAddress);
                }
	      if(tmp)
                {
		  jumpStart = *((Address*)tmp);
		  parsing_printf("\t\tjumpStart adjusted to 0x%lx\n", jumpStart);
                }
            }
	  if(currentBlock->_isrc->isValidAddress(tableStartAddress))
            {
	      tmp = currentBlock->_isrc->getPtrToData(tableStartAddress);
	      if(!tmp)
                {
		  tmp = currentBlock->_isrc->getPtrToInstruction(tableStartAddress);
                }
	      if(tmp)
                {
		  tableStart = *((Address*)tmp);
		  parsing_printf("\t\ttableStart adjusted to 0x%lx\n", jumpStart);
                }
            }
        }


      if (jumpStart == 0) {
#if defined(WITH_SYMTAB_API)
	// If jump table address is a relocation entry, this will be filled by the loader
	// This case is common in shared library where the table address is in the GOT section which is filled by the loader
	// Find the relocation entry for this address and look up its value

	Block* sourceBlock = (*sourceEdges.begin())->src();
	Address blockStart = sourceBlock->start();
	const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
	InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch());
	IA_IAPI IABlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc, sourceBlock);

	SymtabCodeSource *scs = dynamic_cast<SymtabCodeSource *>(IABlock._obj->cs());
	SymtabAPI::Symtab * symtab = scs->getSymtabObject();
	std::vector<SymtabAPI::Region *> regions;
	symtab->getAllRegions(regions);
	for (unsigned index = 0 ; index < regions.size(); index++) {
	  if (regions[index]->getRegionType() == SymtabAPI::Region::RT_RELA || 
	      regions[index]->getRegionType() == SymtabAPI::Region::RT_REL) {
	    std::vector<SymtabAPI::relocationEntry> relocs =
	      regions[index]->getRelocations();	
	    parsing_printf(" \t\trelocation size %d looking for 0x%lx\n", relocs.size(), jumpStartAddress);
	    for (unsigned i = 0; i < relocs.size(); ++i) {
	      parsing_printf(" \t 0x%lx => 0x%lx addend 0x%lx \n", relocs[i].rel_addr(),relocs[i].target_addr(), relocs[i].addend());
	      if (relocs[i].rel_addr() == jumpStartAddress) {
		jumpStart = relocs[i].addend();
		break;
	      }
	    }
	    break;
	  }
	}
#else
        // Can't parse relocation entries without Symtab
        return false;
#endif
      }
      if (tableStart == 0) tableStart = jumpStart;

      if (!tableIsRelative) {
	jumpStart = 0;
      }
      parsing_printf(" jumpStartaddress 0x%lx tableStartAddress 0x%lx \n", jumpStart, tableStart);

      int entriesAdded = 0;
      for(int i = 0; i < maxSwitch; i++)
        {
	  void* ptr = NULL;
	  Address tableEntry = tableStart + i*4; // instruction::size();
	  if(currentBlock->_isrc->isValidAddress(tableEntry))
            {
	      ptr = currentBlock->_isrc->getPtrToInstruction(tableEntry);
            }
	  if(ptr)
            {
	      int jumpOffset = *((int *)ptr);
	      edges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT));
	      parsing_printf("\t\t\t[0x%lx] -> 0x%lx (0x%lx in table)\n", tableEntry,
			     jumpStart+jumpOffset,
			     jumpOffset);
	      ++entriesAdded;
            }
	  else
            {
	      parsing_printf("\t\t\t[0x%lx] -> [INVALID]\n", tableEntry);
            }
        }
      if(!entriesAdded)
        {
	  parsing_printf("%s[%d]: no entries added from jump table, returning false\n", FILE__, __LINE__);
	  return false;
        }
      parsing_printf("%s[%d]: Found %d entries in jump table, returning success\n", FILE__, __LINE__, entriesAdded);
    }

  // Sanity check entries in res
  for (std::vector<std::pair<Address, EdgeTypeEnum> >::iterator iter = edges.begin();
       iter != edges.end(); iter++) {
    if ((iter->first) % 4) {
      parsing_printf("Warning: found unaligned jump table destination 0x%lx for jump at 0x%lx, disregarding table\n",
		     iter->first, initialAddress);
      return false;
    }
  }
  // If we have found a jump table, add the targets to outEdges   
  for (std::vector<std::pair<Address, EdgeTypeEnum> >::iterator iter = edges.begin();
       iter != edges.end(); iter++) {
    parsing_printf("Adding out edge %d/0x%lx\n", iter->second, iter->first);
    outEdges.push_back(*iter);
  }
  return true;
}