Example #1
0
// Build a list of symbols describing instrumentation and relocated functions. 
// To keep this list (somewhat) short, we're doing one symbol per extent of 
// instrumentation + relocation for a particular function. 
// New: do this for one mapped object. 
void BinaryEdit::buildDyninstSymbols(pdvector<Symbol *> &newSyms, 
                                     Region *newSec,
                                     Module *newMod) {
   for (std::vector<SymtabAPI::Symbol *>::iterator iter = newDyninstSyms_.begin();
        iter != newDyninstSyms_.end(); ++iter) {
      (*iter)->setModule(newMod);
      (*iter)->setRegion(newSec);
      newSyms.push_back(*iter);
   }
                                                                              

   for (CodeTrackers::iterator i = relocatedCode_.begin();
        i != relocatedCode_.end(); ++i) {
      Relocation::CodeTracker *CT = *i;
      func_instance *currFunc = NULL;
      Address start = 0;
      unsigned size = 0;
      
      for (Relocation::CodeTracker::TrackerList::const_iterator iter = CT->trackers().begin();
           iter != CT->trackers().end(); ++iter) {
         const Relocation::TrackerElement *tracker = *iter;
         
         func_instance *tfunc = tracker->func();
         
         if (currFunc != tfunc) {
            // Starting a new function
            if (currFunc) {
               // Record the old one
               // currfunc set
               // start set
               size = tracker->reloc() - start;
               
               std::string name = currFunc->prettyName();
               name.append("_dyninst");
               
               Symbol *newSym = new Symbol(name.c_str(),
                                           Symbol::ST_FUNCTION,
                                           Symbol::SL_GLOBAL,
                                           Symbol::SV_DEFAULT,
                                           start,
                                           newMod,
                                           newSec,
                                           size);                                        
               newSyms.push_back(newSym);
            }
            currFunc = tfunc;
            start = tracker->reloc();
            size = 0;
         }
         else {
            // Accumulate size
            size = tracker->reloc() - start;
         }
      }
   }
}
Example #2
0
// Attempt to find the largest contiguous (in virtual address space) region.
// This region must include ".data", and may include the other data like regions
static inline bool find_data_region(pdvector<Address>& all_addr,
				    pdvector<long>& all_size,
				    pdvector<long>& all_disk,
				    unsigned long& data_len, Address& data_off) {
  // Start at data and work back
  assert(all_addr[K_D_INDEX]); assert(all_size[K_D_INDEX]);
  assert(all_addr.size() == all_size.size());

  Address current = all_addr[K_D_INDEX];
  Address min_adr = current;
  Address max_adr = current + all_size[K_D_INDEX];

  unsigned index, max=all_addr.size();

  bool updated=true;
  while (updated) {
    updated = false;
    for (index=0; index<max; index++) {
      if (all_addr[index] && all_size[index] && all_disk[index] &&
	  ((all_addr[index] + all_size[index]) == current)) {
	current = all_addr[index];
	updated = true;
      }
    }
  }
  min_adr = current;

  // Start at data and work forward
  current = max_adr;
  updated=true;
  while (updated) {
    updated = false;
    for (index=0; index<max; index++) {
      if (all_addr[index] && all_size[index] && all_disk[index] && 
	  (all_addr[index] == current)) {
	current = all_addr[index] + all_size[index];
	updated = true;
      }
    }
  }

  max_adr = current;
  
  data_len = (max_adr - min_adr);
  data_off = min_adr;
  assert(min_adr <= all_addr[K_D_INDEX]);
  assert(max_adr >= all_addr[K_D_INDEX] + all_size[K_D_INDEX]);
  return true;
}
Example #3
0
// Return false if the PC is within the jump range of any of our
// multiTramps
bool instPoint::checkInst(pdvector<Address> &checkPCs) {
    
    for (unsigned sI = 0; sI < checkPCs.size(); sI++) {
        Address pc = checkPCs[sI];
        for (unsigned iI = 0; iI < instances.size(); iI++) {
            multiTramp *mt = instances[iI]->multi();
            // No multi -> not installed.
            if (!mt) continue;
            if ((pc > mt->instAddr()) &&
                (pc < (mt->instAddr() + mt->instSize()))) {
                // We have a conflict. Now, we may still be able to make this 
                // work; if we're not conflicting on the actual branch, we
                // may have trap-filled the remainder which allows us to
                // catch and transfer.
                if (pc < (mt->instAddr() + mt->branchSize())) {
                    // We're in the jump area, conflict.
                    fprintf(stderr, "MT conflict (MT from 0x%p to 0x%p, 0x%p to 0x%p dangerous), PC 0x%p\n",
                            (void *)mt->instAddr(),
                            (void *)(mt->instAddr() + mt->instSize()), 
                            (void *)mt->instAddr(),
                            (void *)(mt->instAddr() + mt->branchSize()),
                            (void *)pc);
                    return false;
                }
            }
        }
    }
#if defined(cap_relocation)
    // Yay check relocation
    if (!func()->relocationCheck(checkPCs))
        return false;
#endif

    return true;
}
Example #4
0
/*
 * BPatch_addressSpace::findModuleByAddr
 *
 * Returns the module that contains the specified address, or NULL if the
 * address is not within a module.  Does NOT trigger parsing
 *
 * addr         The address to use for the lookup.
 */
BPatch_module *BPatch_addressSpace::findModuleByAddr(Address addr)
{
   std::vector<AddressSpace *> as;
   getAS(as);
   assert(as.size());

   mapped_object *obj = as[0]->findObject(addr);
   if ( ! obj )
       return NULL;

   const pdvector<mapped_module*> mods = obj->getModules();
   if (mods.size()) {
       return getImage()->findOrCreateModule(mods[0]);
   }
   return NULL;
}
Example #5
0
bool dynamic_linking::getSharedObjects(pdvector<mapped_object *> &mapped_objects) 
{
    pdvector<fileDescriptor> descs;
    
    if (!processLinkMaps(descs))
        return false;
    
    // Skip first entry: always the a.out
    for (unsigned i = 0; i < descs.size(); i++) {
        if (descs[i] != proc->getAOut()->getFileDesc()) {
#if 0
            fprintf(stderr, "DEBUG: match pattern %d, %d, %d, %d, %d\n",
                    descs[i].file() == proc->getAOut()->getFileDesc().file(),
                    descs[i].code() == proc->getAOut()->getFileDesc().code(),
                    descs[i].data() == proc->getAOut()->getFileDesc().data(),
                    descs[i].member() == proc->getAOut()->getFileDesc().member(),
                    descs[i].pid() == proc->getAOut()->getFileDesc().pid());
#endif
            mapped_object *newobj = mapped_object::createMappedObject(descs[i], proc);
            if (newobj == NULL) continue;
            mapped_objects.push_back(newobj);
#if defined(cap_save_the_world)
            setlowestSObaseaddr(descs[i].code());
#endif
        }           
    }
    return true;
} /* end getSharedObjects() */
Example #6
0
bool mapped_module::findFuncVectorByPretty(const pdstring &funcname,
                                           pdvector<int_function *> &funcs)
{
    // For efficiency sake, we grab the image vector and strip out the
    // functions we want.
    // We could also keep them all in modules and ditch the image-wide search; 
    // the problem is that BPatch goes by module and internal goes by image. 
    unsigned orig_size = funcs.size();

    const pdvector<int_function *> *obj_funcs = obj()->findFuncVectorByPretty(funcname);
    if (!obj_funcs) return false;

    for (unsigned i = 0; i < obj_funcs->size(); i++) {
        if ((*obj_funcs)[i]->mod() == this)
            funcs.push_back((*obj_funcs)[i]);
    }
    return funcs.size() > orig_size;
}
Example #7
0
bool dynamic_linking::didLinkMapsChange(u_int &change_type, pdvector<fileDescriptor> &new_descs)
{

  // get list of current shared objects
  const pdvector<mapped_object *> &curr_list = proc->mappedObjects();
  if((change_type == SHAREDOBJECT_REMOVED) && (curr_list.size() == 0)) {
    return false;
  }

  // get the list from the process via /proc
  if (!processLinkMaps(new_descs)) {
      return false;
  }

  unsigned curr_size = curr_list.size();
  unsigned descs_size = new_descs.size();
#if defined(os_linux)
  // The current mapped object list contains the a.out, the 
  // result from processLinkMaps does not.  Correct this  
  // when accounting for size.
  for (unsigned i = 0; i < curr_list.size(); i++) {
    if (curr_list[i] == proc->getAOut()) {
      curr_size--;
      break;
    }
  }

  //Also make sure that we don't start accidently counting the a.out
  for (unsigned i = 0; i < new_descs.size(); i++) {
    if (!new_descs[i].isSharedObject()) {
      descs_size--;
      break;
    }
  }
#endif
 //  override change_type if we have definite evidence of a size chanage
  //  in the link maps
  if (curr_size > descs_size)
       change_type = SHAREDOBJECT_REMOVED;
  else if (curr_size < descs_size)
       change_type = SHAREDOBJECT_ADDED;

  return true;
}
Example #8
0
// Read in from the contiguous data regions, put the data in 'buffer'
static inline bool read_data_region(pdvector<Address>& all_addr,
				    pdvector<long>& all_size,
				    pdvector<long>& all_disk,
				    unsigned long& data_len, Address& data_off,
				    Word *buffer, LDFILE *ldptr) {
  unsigned index, max = all_disk.size();
  Address max_adr = data_off + data_len;
  assert(all_size.size() == all_addr.size());
  assert(all_disk.size() == all_addr.size());
  for (index=0; index<max; index++) {
    if ((all_addr[index] >= data_off) &&
	((all_addr[index] + all_size[index]) <= max_adr)) {
      if (ldfseek(ldptr, all_disk[index], SEEK_SET) == -1) return false;
      Word *buf_temp = buffer + (all_addr[index] - data_off);
      if (ldfread((void*) buf_temp, 1, all_size[index], ldptr) != all_size[index])
	return false;
    }
  }
  return true;
}
Example #9
0
static void emitNeededCallRestores(codeGen &gen, pdvector<Register> &saves)
{
    for (unsigned i=0; i<saves.size(); i++) {
      switch (saves[i]) {
          case REGNUM_EAX:
              emitSimpleInsn(POP_EAX, gen);
              break;
          case REGNUM_EBX:
              emitSimpleInsn(POP_EBX, gen);
              break;
          case REGNUM_ECX:
              emitSimpleInsn(POP_ECX, gen);
              break;
          case REGNUM_EDX:
              emitSimpleInsn(POP_EDX, gen);
              break;
          case REGNUM_EDI:
              emitSimpleInsn(POP_EDI, gen);
              break;
      }
    }
    saves.clear();
}
Example #10
0
pdvector< pdvector<resourceHandle> >
callGraphDisplay::getSelections(bool &wholeProgram,
				pdvector<unsigned> &wholeProgramFocus) const {
  // returns a vector[num-hierarchies] of vector of selections.
  // The number of hierarchies is defined as the number of children of the
  // root node.  If "Whole Program" was selection, it isn't returned with
  // the main result; it's returned by modifying the 2 params
  const unsigned numHierarchies = rootPtr->getNumChildren();
  
  pdvector < pdvector<resourceHandle> > result(numHierarchies);

  bool wholeProgramImplicit = true; // so far...

  for (unsigned i=0; i < numHierarchies; i++) {
    where4tree<callGraphRootNode> *hierarchyRoot = rootPtr->getChildTree(i);
    pdvector <const callGraphRootNode *> thisHierarchySelections = 
      hierarchyRoot->getSelections();
    
    if (thisHierarchySelections.size()==0)
      // add hierarchy's root item
      thisHierarchySelections += &hierarchyRoot->getNodeData();
    else
      // since the hierarchy selection was not empty, we do _not_
      // want to implicitly select whole-program
      wholeProgramImplicit = false;
    
    result[i].resize(thisHierarchySelections.size());
    for (unsigned j=0; j < thisHierarchySelections.size(); j++)
      result[i][j] = thisHierarchySelections[j]->getUniqueId();
  }
  
  wholeProgram = wholeProgramImplicit || rootPtr->isHighlighted();
  if (wholeProgram) {
    // write to wholeProgramFocus:
    wholeProgramFocus.resize(numHierarchies);
    for (unsigned i=0; i < numHierarchies; i++) {
      where4tree<callGraphRootNode> *hierarchyRoot = rootPtr->getChildTree(i);
      const callGraphRootNode &hierarchyRootData = hierarchyRoot->getNodeData();
      unsigned hierarchyRootUniqueId = hierarchyRootData.getUniqueId();
      wholeProgramFocus[i] = hierarchyRootUniqueId;
    }
  }
  
  return result;
}
Example #11
0
void instrCodeNode::prepareForSampling(
                                  const pdvector<threadMetFocusNode *> &thrNodes)
{
  if(! instrLoaded()) return;

  for(unsigned i=0; i<thrNodes.size(); i++) {
    threadMetFocusNode *curThrNode = thrNodes[i];
    V.sampledDataNode->prepareForSampling(curThrNode->getThreadIndex(), 
                                          curThrNode->getValuePtr());
  }

#ifdef PAPI
  if (V.hwEvent != NULL) {
    V.hwEvent->enable();
  }
#endif

}
Example #12
0
void registerSpace::createRegSpaceInt(pdvector<registerSlot *> &registers,
                                      registerSpace *rs) {
    for (unsigned i = 0; i < registers.size(); i++) {
        Register reg = registers[i]->number;

        rs->registers_[reg] = registers[i];

        rs->registersByName[registers[i]->name] = registers[i]->number;

        switch (registers[i]->type) {
        case registerSlot::GPR: {
	  bool physical = true;
#if defined(arch_x86) || defined(arch_x86_64)
	  if (rs->addr_width == 4)
	    physical = false;
#endif
	  if (physical) rs->physicalRegisters_[reg] = registers[i];

	  rs->GPRs_.push_back(registers[i]);
	  break;
	}
        case registerSlot::FPR:
	  rs->FPRs_.push_back(registers[i]);
	  break;
        case registerSlot::SPR:
	  rs->SPRs_.push_back(registers[i]);
	  break;
        case registerSlot::realReg:
	  rs->physicalRegisters_[reg] = registers[i];
	  rs->realRegisters_.push_back(registers[i]);
	  break;
        default:
            fprintf(stderr, "Error: no match for %d\n", registers[i]->type);
            assert(0);
            break;
        }
    }

}
Example #13
0
static void emitNeededCallSaves(codeGen &gen, Register regi, 
                           pdvector<Register> &extra_saves)
{
    extra_saves.push_back(regi);
    switch (regi) {
        case REGNUM_EAX:
            emitSimpleInsn(PUSHEAX, gen);
            break;
        case REGNUM_EBX:
            emitSimpleInsn(PUSHEBX, gen);
            break;
        case REGNUM_ECX:
            emitSimpleInsn(PUSHECX, gen);
            break;
        case REGNUM_EDX:
            emitSimpleInsn(PUSHEDX, gen);
            break;
        case REGNUM_EDI:
            emitSimpleInsn(PUSHEDI, gen);
            break;
    }
}
Example #14
0
bool SignalHandler::waitForEvent(pdvector<EventRecord> &events_to_handle)
{
    assert(waitLock);

    signal_printf("%s[%d]: waitForEvent, events_to_handle(%d), idle_flag %d\n",
                  FILE__, __LINE__, events_to_handle.size(), idle());

    while (idle()) {
        // Our eventlocks are paired mutexes and condition variables; this
        // is actually _not_ what we want because we want to be able to
        // wait on different things but have the same global mutex. So we fake it
        // by carefully unlocking and relocking things. 
        
        // We now wait until _we_ are signalled by the generator; so we grab
        // our signal lock, give up the global mutex lock, and then wait; after
        // we're signalled we take the global mutex before giving up our own 
        // waitLock.
        
        waitingForWakeup_ = true;
        signal_printf("%s[%d]: acquiring waitLock lock...\n", FILE__, __LINE__);
        waitLock->_Lock(FILE__, __LINE__);
        signal_printf("%s[%d]: releasing global mutex...\n", FILE__, __LINE__);
        assert(eventlock->depth() == 1);
        eventlock->_Unlock(FILE__, __LINE__);
        
        signal_printf("%s[%d]: sleeping for activation\n", FILE__, __LINE__);
        waitLock->_WaitForSignal(FILE__, __LINE__);
        
        signal_printf("%s[%d]: woken, reacquiring global lock...\n", FILE__, __LINE__);
        eventlock->_Lock(FILE__, __LINE__);
        signal_printf("%s[%d]: woken, releasing waitLock...\n", FILE__, __LINE__);
        waitLock->_Unlock(FILE__, __LINE__);
        waitingForWakeup_ = false;        
    }
    
    return true;
}
Example #15
0
// findChangeToLinkMaps: This routine returns a vector of shared objects
// that have been deleted or added to the link maps as indicated by
// change_type.  If an error occurs it sets error_occured to true.
bool dynamic_linking::findChangeToLinkMaps(u_int &change_type,
					   pdvector<mapped_object *> &changed_objects) 
{
  pdvector<fileDescriptor> new_descs;
  if (!didLinkMapsChange(change_type, new_descs)) {
    return false;
  }

  const pdvector<mapped_object *> &curr_list = proc->mappedObjects();


#if 0
  fprintf(stderr, "CURR_LIST:\n");
  for (unsigned foo = 0; foo < curr_list.size(); foo++) {
      fprintf(stderr, "%d: %s\0x%x\n",
              foo, curr_list[foo]->fileName().c_str(), curr_list[foo]->codeBase());
  }
#endif

  // if change_type is add then figure out what has been added
  if(change_type == SHAREDOBJECT_ADDED) {
      // Look for the one that doesn't match
      for (unsigned int i=0; i < new_descs.size(); i++) {

	  bool found = false;
	  for (unsigned int j = 0; j < curr_list.size(); j++) {
#if 0 
              fprintf(stderr, "Comparing %s/0x%x/0x%x/%s/%d to %s/0x%x/0x%x/%s/%d\n",
                      new_descs[i].file().c_str(),
                      new_descs[i].code(),
                      new_descs[i].data(),
                      new_descs[i].member().c_str(),
                      new_descs[i].pid(),
                      curr_list[j]->getFileDesc().file().c_str(),
                      curr_list[j]->getFileDesc().code(),
                      curr_list[j]->getFileDesc().data(),
                      curr_list[j]->getFileDesc().member().c_str(),
                      curr_list[j]->getFileDesc().pid());
#endif
              if (new_descs[i] == curr_list[j]->getFileDesc()) {
                  found = true;
                  break;
              }
	  }
	  if (!found) {
#if 0
              fprintf(stderr, "Adding %s/%s\n",
                      new_descs[i].file().c_str(),
                      new_descs[i].member().c_str());
#endif
              mapped_object *newobj = mapped_object::createMappedObject(new_descs[i],
                                                                        proc);
              if (!newobj) continue;

              changed_objects.push_back(newobj);

          // SaveTheWorld bookkeeping
#if defined(cap_save_the_world)
              char *tmpStr = new char[1+strlen(newobj->fileName().c_str())];
              strcpy(tmpStr, newobj->fileName().c_str());
              if( !strstr(tmpStr, "libdyninstAPI_RT.so") && 
                  !strstr(tmpStr, "libelf.so")){
                  //bperr(" dlopen: %s \n", tmpStr);
                  newobj->openedWithdlopen();
              }
              setlowestSObaseaddr(newobj->codeBase());
              delete [] tmpStr;	              
              // SaveTheWorld bookkeeping
#endif

	  }
      }
  }
  // if change_type is remove then figure out what has been removed
  else if((change_type == SHAREDOBJECT_REMOVED) && (curr_list.size())) {
      // Look for the one that's not in descs
      bool stillThere[curr_list.size()];
      for (unsigned k = 0; k < curr_list.size(); k++) 
          stillThere[k] = false;
#if defined(os_linux) || defined(os_solaris)
      // Linux never includes the a.out in its list of libraries. This makes a
      // certain amount of sense, but is still annoying.
      // Solaris throws it away; so hey.
      stillThere[0] = true;
#endif
      
      for (unsigned int i=0; i < new_descs.size(); i++) {
	  for (unsigned int j = 0; j < curr_list.size(); j++) {
              if (new_descs[i] == curr_list[j]->getFileDesc()) {
                  stillThere[j] = true;
                  break;
              }
	  }
      }

      for (unsigned l = 0; l < curr_list.size(); l++) {
          if (!stillThere[l]) {
              changed_objects.push_back(curr_list[l]);
          }
      }
  }
  return true;
}
Example #16
0
/*
 * BPatch_image::createInstPointAtAddr
 *
 * Returns a pointer to a BPatch_point object representing an
 * instrumentation point at the given address. If the BPatch_function
 * argument is given it has to be the function that address belongs to or NULL.
 * The function is used to bypass the function that the address belongs to
 * The alternative argument is used to retrieve the point if the new point
 * intersects with another already existing one.
 *
 * Returns the pointer to the BPatch_point on success, or NULL upon
 * failure.
 *
 * address	The address that the instrumenation point should refer to.
 */
BPatch_point *BPatch_image::createInstPointAtAddrWithAlt(void *address,
        BPatch_point** alternative,
        BPatch_function* bpf)
{
    Address address_int = (Address) address;

    unsigned i;
    process *llproc = proc->llproc;
    int_function *func = NULL;

    if (bpf) {
        func = bpf->func;
    }
    else {
        func = llproc->findFuncByAddr(address_int);
    }

    if (func == NULL) return NULL;

    /* See if there is an instPoint at this address */
    instPoint *p = NULL;

    if ((p = func->findInstPByAddr(address_int))) {
        return proc->findOrCreateBPPoint(NULL, p, BPatch_locInstruction);
    }

    /* Look in the regular instPoints of the enclosing function. */
    /* This has an interesting side effect: "instrument the first
       instruction" may return with "entry instrumentation", which can
       have different semantics. */

    // If it's in an uninstrumentable function, just return an error.
    if (!func->isInstrumentable()) {
        return NULL;
    }

    const pdvector<instPoint *> entries = func->funcEntries();
    for (unsigned t = 0; t < entries.size(); t++) {
        assert(entries[t]);
        if (entries[t]->match(address_int)) {
            return proc->findOrCreateBPPoint(NULL, entries[t], BPatch_entry);
        }
    }

    const pdvector<instPoint*> &exits = func->funcExits();
    for (i = 0; i < exits.size(); i++) {
        assert(exits[i]);
        if (exits[i]->match(address_int)) {
            return proc->findOrCreateBPPoint(NULL, exits[i], BPatch_exit);
        }
    }

    const pdvector<instPoint*> &calls = func->funcCalls();
    for (i = 0; i < calls.size(); i++) {
        assert(calls[i]);
        if (calls[i]->match(address_int))  {
            return proc->findOrCreateBPPoint(NULL, calls[i], BPatch_subroutine);
        }
    }

    if(alternative)
        *alternative = NULL;

    /* We don't have an instPoint for this address, so make one. */
    instPoint *newInstP = instPoint::createArbitraryInstPoint(address_int, proc->llproc);
    if (!newInstP) return NULL;

    return proc->findOrCreateBPPoint(NULL, newInstP, BPatch_locInstruction);
}
Example #17
0
// processLinkMaps: get a list of all loaded objects in fileDescriptor form.
bool dynamic_linking::processLinkMaps(pdvector<fileDescriptor> &descs) {
    
    int proc_fd = proc->getRepresentativeLWP()->get_fd();
    if(!proc_fd){ return false;}

    // step 2: get the runtime loader table from the process
    Address ldr_base_addr;
    ldr_context first;
    ldr_module module;

    assert(proc->readDataSpace((const void*)LDR_BASE_ADDR,sizeof(Address), &ldr_base_addr, true));
    assert(proc->readDataSpace((const void*)ldr_base_addr,sizeof(ldr_context), &first, true));
    assert(proc->readDataSpace((const void *) first.head,sizeof(ldr_module), &module, true));
    
    while (module.next != first.head) {
      if (module.nregions == 0)
	{ 
	  assert(proc->readDataSpace((const void *) module.next,sizeof(ldr_module), &module,true));
	  continue;
        }
      pdstring obj_name = pdstring(readDataString(proc, module.name));
      ldr_region *regions;
      
      regions = (ldr_region *) malloc(module.nregions * sizeof(ldr_region));
      assert(proc->readDataSpace((const void *) module.regions, 
				 sizeof(ldr_region)*module.nregions, regions, true));
      
      long offset = regions[0].mapaddr - regions[0].vaddr;
#ifdef notdef
      if (offset) {
	bperr("*** shared lib at non-default offset **: ");
	bperr("    %s\n", obj_name.c_str());
	bperr("    offset = %ld\n", offset);
      } else {
	bperr("*** shared lib **: ");
	bperr("    %s\n", obj_name.c_str());
	bperr("    at = %ld\n", regions[0].mapaddr);
      }
#endif
      
      for (int i=0; i < module.nregions; i++) {
	long newoffset = regions[i].mapaddr - regions[i].vaddr;
	if (newoffset != offset) {
	  bperr( "shared lib regions have different offsets\n");
	}
	regions[i].name = (long unsigned) readDataString(proc,
							 (void *) regions[i].name);
	// bperr("  region %d (%s) ", i, regions[i].name);
	// bperr("addr = %lx, ", regions[i].vaddr);
	// bperr("mapped at = %lx, ", regions[i].mapaddr);
	// bperr("size = %x\n", regions[i].size);
      }
      descs.push_back(fileDescriptor(obj_name, 
				     offset,
				     offset,
				     true));

      free(regions);
      assert(proc->readDataSpace((const void *) module.next,sizeof(ldr_module), &module,true));
    }
    return true;
}
Example #18
0
bool dynamic_linking::handleIfDueToSharedObjectMapping(EventRecord &ev, 
                                                       pdvector<mapped_object*> &changed_objects)
{

   struct dyn_saved_regs regs;

   // multi-threaded: possible one of many threads hit the breakpoint

   pdvector<Frame> activeFrames;
   if (!proc->getAllActiveFrames(activeFrames)) {
      return false;
   }

   dyn_lwp *brk_lwp = NULL;
   sharedLibHook *hook = NULL;
   for (unsigned frame_iter = 0; frame_iter < activeFrames.size();frame_iter++)
   {
       hook = reachedLibHook(activeFrames[frame_iter].getPC());
       if (hook) {
           brk_lwp = activeFrames[frame_iter].getLWP();
           break;
       }
   }

   if (brk_lwp || force_library_load) {
       // find out what has changed in the link map
      // and process it
      r_debug debug_elm;
      if(!proc->readDataSpace((caddr_t)(r_debug_addr),
                              sizeof(r_debug),(caddr_t)&(debug_elm),true)) {
          // bperr("read failed r_debug_addr = 0x%x\n",r_debug_addr);
          return false;
      }
      
      // if the state of the link maps is consistent then we can read
      // the link maps, otherwise just set the r_state value
      ev.what = r_state;   // previous state of link maps 
      r_state = debug_elm.r_state;  // new state of link maps

      if( debug_elm.r_state == 0) {
          // figure out how link maps have changed, and then create
         // a list of either all the removed shared objects if this
         // was a dlclose or the added shared objects if this was a dlopen
      
         // kludge: the state of the first add can get screwed up
         // so if both change_type and r_state are 0 set change_type to 1
         if(ev.what == 0) ev.what = SHAREDOBJECT_ADDED;
         findChangeToLinkMaps((u_int &)ev.what, changed_objects);
      } 
      
      // Don't need to reset PC
      if (!force_library_load) {
          assert(brk_lwp);
          
          // Get the registers for this lwp
          brk_lwp->getRegisters(&regs);
#if defined(arch_sparc)
          // change the pc so that it will look like the retl instr 
          // completed: set PC to o7 in current frame
          // we can do this because this retl doesn't correspond to 
          // an instrumentation point, so we don't have to worry about 
          // missing any instrumentation code by making it look like the
          // retl has already happend
          
          // first get the value of the stackpointer
          Address o7reg = regs.theIntRegs[R_O7];
          o7reg += 2*instruction::size();
          if(!(brk_lwp->changePC(o7reg, NULL))) {
              // bperr("error in changePC handleIfDueToSharedObjectMapping\n");
              return false;
          }
#else //x86
      // set the pc to the "ret" instruction
          Address next_pc = regs[R_PC] + instruction::size();
          if (!brk_lwp->changePC(next_pc))
              return false;
#endif
      }
      if (changed_objects.size() == 0) ev.what = 0;
      return true;

   }
  return false;
}
Example #19
0
Register registerSpace::getScratchRegister(codeGen &gen, pdvector<Register> &excluded, bool noCost, bool realReg) {
  static int num_allocs = 0;
  
  pdvector<registerSlot *> couldBeStolen;
  pdvector<registerSlot *> couldBeSpilled;
  
  debugPrint();

  registerSlot *toUse = NULL;

  regalloc_printf("Allocating register: selection is %s\n",
		  realReg ? (realRegisters_.empty() ? "GPRS" : "Real registers") : "GPRs");

  pdvector<registerSlot *> &regs = (realReg ? (realRegisters_.empty() ? GPRs_ : realRegisters_ ) : GPRs_ );
  regalloc_printf("%d options in registers\n", regs.size());

  for (unsigned i = 0; i < regs.size(); i++) {
    registerSlot *reg = regs[i];
      
    regalloc_printf("%s[%d]: getting scratch register, examining %d of %d: reg %d (%s), offLimits %d, refCount %d, liveState %s, keptValue %d\n",
		    FILE__, __LINE__, i, regs.size(),
		    reg->number,
		    reg->name.c_str(),
		    reg->offLimits,
		    reg->refCount,
		    (reg->liveState == registerSlot::live) ? "live" : ((reg->liveState == registerSlot::dead) ? "dead" : "spilled"),
		    reg->keptValue);
      
    bool found = false;
    for (unsigned int i = 0; i < excluded.size(); ++i) {
      Register &ex_reg = excluded[i];
      if (reg->number == ex_reg) {
	found = true;
	break;
      }
    }

        if (found) continue;

        if (reg->offLimits) continue;
        if (reg->refCount > 0) continue;
        if (reg->liveState == registerSlot::live) {
            // Don't do anything for now, but add to the "could be" list
            couldBeSpilled.push_back(reg);
            continue;
        }
        if (reg->keptValue) {
            // As above
            couldBeStolen.push_back(reg);
            continue;
        }
        // Hey, got one.
        toUse = reg;
        break;
    }

    if (toUse == NULL) {
        // Argh. Let's assume spilling is cheaper
        for (unsigned i = 0; i < couldBeSpilled.size(); i++) {
            if (spillRegister(couldBeSpilled[i]->number, gen, noCost)) {
                toUse = couldBeSpilled[i];
                break;
            }
        }
    }
    
    // Still?
    if (toUse == NULL) {
        for (unsigned i = 0; i < couldBeStolen.size(); i++) {
            if (stealRegister(couldBeStolen[i]->number, gen, noCost)) {
                toUse = couldBeStolen[i];
                break;
            }
        }
    }

    if (toUse == NULL) {
        // Crap.
      // debugPrint();
        return REG_NULL;
    }

    toUse->alloc_num = num_allocs;
    num_allocs++;

  toUse->markUsed(false);

  gen.markRegDefined(toUse->number);

  return toUse->number;
}
Example #20
0
int insnCodeGen::createStackFrame(codeGen &gen, int numRegs, pdvector<Register>& freeReg, pdvector<Register>& excludeReg){
assert(0);
//#warning "This function is not implemented yet!"
		return freeReg.size();
}
Example #21
0
bool SignalHandler::handleForkExit(EventRecord &ev, bool &continueHint)
{
     signal_printf("%s[%d]: Welcome to FORK EXIT for process %d\n",
                   FILE__, __LINE__, ev.proc->getPid());

     process *proc = ev.proc;
     // Fork handler time
     extern pdvector<process*> processVec;
     int childPid = INFO_TO_PID(ev.info);

     if (childPid == getpid()) {
         // this is a special case where the normal createProcess code
         // has created this process, but the attach routine runs soon
         // enough that the child (of the mutator) gets a fork exit
         // event.  We don't care about this event, so we just continue
         // the process - jkh 1/31/00
         signal_printf("%s[%d]: received FORK on self pid\n",
                       FILE__, __LINE__);
         continueHint = true;
         return true;
     } else if (childPid > 0) {

         unsigned int i;
         for (i=0; i < processVec.size(); i++) {
             if (processVec[i] &&
                 (processVec[i]->getPid() == childPid)) break;
         }
         if (i== processVec.size()) {
             // this is a new child, register it with dyninst
             // Note: we need to wait for the child process to be created.

             sleep(1);

             // For now, we sleep (apparently), but the better solution is to
             // loop waiting for the child to be created and then attach to it.
             // We have seen the following order:
             // Parent exits fork
             // We get notification -- but no child yet.
             // Child is created
             // This seems to be OS dependent on who goes first - parent or child.

             // We leave the parent paused until the child is finished,
             // so that we can be sure to copy everything correctly.

             process *theChild = ev.proc->sh->newProcess(proc, (int) childPid, -1);
             if (!theChild)
               return false;
   
             proc->handleForkExit(theChild);

             // This may have been mucked with during the fork callback
	     // If we're still paused, then hit run. It'd be nice if there was a 
	     // way to let the user say "stay paused!" -- bernat
	     if (proc->sh->syncRunWhenFinished_ != runRequest) {
	       signal_printf("%s[%d]: running parent post-FORK: overriding syncContinueState\n",
			     FILE__, __LINE__);
	       proc->sh->overrideSyncContinueState(runRequest);
	     }
             continueHint = true;
             // Unlike normal, we want to start this guy up running (the user can pause if desired in
             // the callback)
	     if (theChild->sh->syncRunWhenFinished_ != runRequest) {
	       signal_printf("%s[%d]: running child post-FORK: overriding syncContinueState\n",
			     FILE__, __LINE__);
	       theChild->sh->overrideSyncContinueState(runRequest);
	     }
             theChild->continueProc();
        }
     }
     else {
         // Child signalGenerator may execute this guy ; leave it untouched.

         // If we've already received the stop (AKA childForkStopAlreadyReceived
         // is true), then we're getting double-signalled due to odd Linux behavior.
         // Continue the process.
         // If not, then set to true and leave paused.

         signal_printf("%s[%d]: child case in fork handling; stopAlreadyReceived = %d\n",
                       FILE__, __LINE__, proc->sh->childForkStopAlreadyReceived_);

         // Might be a different signal generator from us...
         if (proc->sh->childForkStopAlreadyReceived_) {
	   continueHint = true;
         }
     }
    return true;
}
Example #22
0
int EmitterIA32::emitCallParams(codeGen &gen, 
                              const pdvector<AstNodePtr> &operands,
                              func_instance *target, 
                              pdvector<Register> &extra_saves, 
                              bool noCost)
{
    callType call_conven = target->getCallingConvention();
    int estimatedFrameSize = 0;
    pdvector <Register> srcs;
    Register ecx_target = REG_NULL, edx_target = REG_NULL;
    Address unused = ADDR_NULL;
    const int num_operands = operands.size();

    switch (call_conven) {
        case unknown_call:
        case cdecl_call:
        case stdcall_call:
          //Push all registers onto stack
          for (unsigned u = 0; u < operands.size(); u++) {
              Register src = REG_NULL;
              Address unused = ADDR_NULL;
              if (!operands[u]->generateCode_phase2( gen, false, unused, src)) assert(0);
              assert(src != REG_NULL);
              srcs.push_back(src);
          }
          break;
    case thiscall_call:
        //Allocate the ecx register for the 'this' parameter
        if (num_operands) {
            //result = gen.rs()->allocateSpecificRegister(gen, REGNUM_ECX, false);
            //if (!result) {
            //    emitNeededCallSaves(gen, REGNUM_ECX, extra_saves);
            //}
            if (!operands[0]->generateCode_phase2(gen, 
                                                  noCost, 
                                                  unused, ecx_target)) assert(0);
        }
        srcs.push_back(Null_Register);
        //Push other registers onto the stack
        for (unsigned u = 1; u < operands.size(); u++) {
              Register src = REG_NULL;
              Address unused = ADDR_NULL;
              if (!operands[u]->generateCode_phase2( gen, false, unused, src)) assert(0);
              assert(src != REG_NULL);
              srcs.push_back(src);
        }     
        break;
    case fastcall_call:
        if (num_operands) {
            //Allocate the ecx register for the first parameter
            //ecx_target = gen.rs()->allocateSpecificRegister(gen, REGNUM_ECX, false);
            //if (!ecx_target) {
            //    emitNeededCallSaves(gen, REGNUM_ECX, extra_saves);
            //}
        }
        if (num_operands > 1) {
            //Allocate the edx register for the second parameter
            //edx_target = gen.rs()->allocateSpecificRegister(gen, REGNUM_EDX, false);
            //if (!edx_target) {
            //    emitNeededCallSaves(gen, REGNUM_EDX, extra_saves);
            //}
        }
        if (num_operands) {
            if (!operands[0]->generateCode_phase2(gen, 
                                                  noCost, 
                                                  unused, ecx_target)) assert(0);
        }
        if (num_operands > 1) {
            if (!operands[1]->generateCode_phase2(gen, 
                                                  noCost, unused, edx_target)) assert(0);
        }
        srcs.push_back(Null_Register);
        srcs.push_back(Null_Register);

        //Push other registers onto the stack
        for (unsigned u = 2; u < operands.size(); u++) {
              Register src = REG_NULL;
              Address unused = ADDR_NULL;
              if (!operands[u]->generateCode_phase2( gen, false, unused, src)) assert(0);
              assert(src != REG_NULL);
              srcs.push_back(src);
        }
        break;
    default:
        fprintf(stderr, "Internal error.  Unknown calling convention\n");
        assert(0);
    }

    // push arguments in reverse order, last argument first
    // must use int instead of unsigned to avoid nasty underflow problem:
    for (int i=srcs.size() - 1; i >= 0; i--) {
       if (srcs[i] == Null_Register) continue;
	   RealRegister r = gen.rs()->loadVirtual(srcs[i], gen);
	   ::emitPush(r, gen);
       estimatedFrameSize += 4;
       if (operands[i]->decRefCount())
          gen.rs()->freeRegister(srcs[i]);
    }

    if (ecx_target != REG_NULL) {
        //Store the parameter in ecx
		gen.rs()->loadVirtualToSpecific(ecx_target, RealRegister(REGNUM_ECX), gen);
    }

    if (edx_target != REG_NULL) {
		gen.rs()->loadVirtualToSpecific(edx_target, RealRegister(REGNUM_EDX), gen);
    }
    return estimatedFrameSize;
}
Example #23
0
void HybridAnalysis::virtualFreeCB(BPatch_point *, void *t) {
	assert(virtualFreeAddr_ != 0);
	unsigned type = (unsigned) t;
	cerr << "virtualFree [" << hex << virtualFreeAddr_ << "," << virtualFreeAddr_ + (unsigned) virtualFreeSize_ << "], " << (unsigned) type << dec << endl;

	Address pageSize = proc()->lowlevel_process()->getMemoryPageSize();

	// Windows page-aligns everything.

	unsigned addrShift = virtualFreeAddr_ % pageSize;
	unsigned sizeShift = pageSize - (virtualFreeSize_ % pageSize);

	virtualFreeAddr_ -= addrShift;

	if (type != MEM_RELEASE)
	{
		virtualFreeSize_ += addrShift + sizeShift;
	}

	// We need to:
	// 1) Remove any function with a block in the deleted range
	// 2) Remove memory translation for that range
	// 3) Skip trying to set permissions for any page in the range.

	// DEBUG!
	if (1 || type == MEM_RELEASE)
	{
		mapped_object *obj = proc()->lowlevel_process()->findObject(virtualFreeAddr_);

		if (!obj) return;
		virtualFreeAddr_ = obj->codeBase();
		virtualFreeSize_ = obj->imageSize();
		// DEBUG!
		cerr << "Removing VirtualAlloc'ed shared object " << obj->fileName() << endl;
      image *img = obj->parse_img();
		proc()->lowlevel_process()->removeASharedObject(obj);
		virtualFreeAddr_ = 0;
      // Since removeASharedObject doesn't actually delete the object, 
      // or its image (even if its refCount==0), make sure the image
      // goes away from global datastructure allImages
      for (unsigned int i=0; i < allImages.size(); i++) {
         if (img == allImages[i]) {
            allImages[i] = allImages.back();
            allImages.pop_back();
         }
      }
		return;
	}

	std::set<func_instance *> deletedFuncs;
	for (Address i = virtualFreeAddr_; i < (virtualFreeAddr_ + virtualFreeSize_); ++i) {
		proc()->lowlevel_process()->findFuncsByAddr(i, deletedFuncs);
	}
	for (std::set<func_instance *>::iterator iter = deletedFuncs.begin();
		iter != deletedFuncs.end(); ++iter)
	{
		BPatch_function * bpfunc = proc()->findOrCreateBPFunc(*iter, NULL);
		if (!bpfunc) continue;
        PatchAPI::PatchModifier::remove(bpfunc->lowlevel_func());
	}

	proc()->lowlevel_process()->getMemEm()->removeRegion(virtualFreeAddr_, virtualFreeSize_);
	// And nuke the RT cache

	proc()->lowlevel_process()->proc()->flushAddressCache_RT(virtualFreeAddr_, virtualFreeSize_);

	virtualFreeAddr_ = 0;
	return;
}
Example #24
0
// processLinkMaps: This routine is called by getSharedObjects to  
// process all shared objects that have been mapped into the process's
// address space.  This routine reads the link maps from the application 
// process to find the shared object file base mappings. It returns 0 on error.
bool dynamic_linking::processLinkMaps(pdvector<fileDescriptor> &descs) {
   r_debug debug_elm;
   if(!proc->readDataSpace((caddr_t)(r_debug_addr),
                        sizeof(r_debug),(caddr_t)&(debug_elm),true)) {
      // bperr("read d_ptr_addr failed r_debug_addr = 0x%lx\n",r_debug_addr);
      return 0;
   }

   // get each link_map object
   Link_map *next_link_map = debug_elm.r_map;
   Address next_addr = (Address)next_link_map; 
   
   while(next_addr != 0){
       Link_map link_elm;

       if(!proc->readDataSpace((caddr_t)(next_addr),
                               sizeof(Link_map),(caddr_t)&(link_elm),true)) {
           logLine("read next_link_map failed\n");
           return 0;
       }
       // get file name
       char f_name[256]; // assume no file names greater than 256 chars
       // check to see if reading 256 chars will go out of bounds
       // of data segment
       u_int f_amount = 256;
       bool done = false;
       for(u_int i=0; (i<256) && (!done); i++){
           if(!proc->readDataSpace((caddr_t)((u_int)(link_elm.l_name)+i),
                                   sizeof(char),(caddr_t)(&(f_name[i])),true)){
           }
           if(f_name[i] == '\0'){
               done = true;
               f_amount = i+1;
           }
       }
       f_name[f_amount-1] = '\0';
       pdstring obj_name = pdstring(f_name);

      parsing_cerr << 
         "dynamicLinking::processLinkMaps(): file name of next shared obj="
                     << obj_name << endl;

      // create a mapped_object and add it to the list
      // kludge: ignore the entry if it has the same name as the
      // executable file...this seems to be the first link-map entry
      // VG(09/25/01): also ignore if address is 65536 or name is (unknown)
      if(obj_name != proc->getAOut()->fileName() && 
         obj_name != proc->getAOut()->fullName() &&
         link_elm.l_addr != 65536 &&
         obj_name != "(unknown)"
         //strncmp(obj_name.c_str(), "(unknown)", 10)
         ) {
          
          fileDescriptor desc = fileDescriptor(obj_name, link_elm.l_addr,
                                               link_elm.l_addr,
                                               true);
          descs.push_back(desc);          
      }
      
      next_addr = (Address)link_elm.l_next;
   }

   return true;
}