Example #1
0
Matcher::sp_iterator Matcher::setSourceFile(StringRef target)
{
  // If target is empty, we assume it's a self-testing:
  // i.e., the beginning of the compilation unit will be
  // used.
  if (target.empty()) {
    processSubprograms(module); 
    patchname="";
    initialized = true;
    return sp_begin();
  }
  std::string oldfile = filename;
  if (!initName(target))
    return sp_end();
  if (oldfile == filename) {
    if (DEBUG_MATCHER) 
      errs() << "Target source didn't change since last time, reuse old processing.\n";
  }
  else {
    cu_iterator ci = matchCompileUnit(target);
    if (ci == cu_end())
      return sp_end();
    MySPs.clear();
    processSubprograms(*ci);
    std::sort(MySPs.begin(), MySPs.end(), cmpDISPCopy);
    if (DEBUG_MATCHER) 
      dumpSPs();
  }
  initialized = true;
  // shouldn't just return MySPs.begin(). because a CU may contain SPs from other CUs.
  return slideToFile(filename); 
}
Example #2
0
/*----------------------------------------------------------------------
  Reading input somehow failed and we need to shutdown now

 Args:  none

 Result: pine exits

  ---*/
void
read_bail(void)
{
    dprint((1, "read_bail: cleaning up\n"));

    /* Do not bail out on a tcp timeout, instead close the troublesome stream */
    if(ps_global->tcptimeout && some_stream_is_locked()){
      ps_global->read_bail = 1;
      return;
    }
    end_signals(1);

    /*
     * This gets rid of temporary cache files for remote addrbooks.
     */
    completely_done_with_adrbks();

    /*
     * This flushes out deferred changes and gets rid of temporary cache
     * files for remote config files.
     */
    if(ps_global->prc){
	if(ps_global->prc->outstanding_pinerc_changes)
	  write_pinerc(ps_global, Main, WRP_NOUSER);

	if(ps_global->prc->rd)
	  rd_close_remdata(&ps_global->prc->rd);
	
	free_pinerc_s(&ps_global->prc);
    }

    /* as does this */
    if(ps_global->post_prc){
	if(ps_global->post_prc->outstanding_pinerc_changes)
	  write_pinerc(ps_global, Post, WRP_NOUSER);

	if(ps_global->post_prc->rd)
	  rd_close_remdata(&ps_global->post_prc->rd);
	
	free_pinerc_s(&ps_global->post_prc);
    }

    sp_end();

    dprint((1, "done with read_bail clean up\n"));

    imap_flush_passwd_cache(TRUE);
    end_keyboard(F_ON(F_USE_FK,ps_global));
    end_tty_driver(ps_global);
    if(filter_data_file(0))
      our_unlink(filter_data_file(0));

    exit(0);
}
Example #3
0
void
sp_abort()
{
    struct sp_table *st;

    for (st = sp_first_update(); st != NULL; st = sp_next_update()) {
        sp_undo_mod_dir(st);
    }
    sp_clear_updates();

    sp_end();
}
Example #4
0
/* *
 * Adjust sp_iterator to the starting position of
 * the target source file region.
 *
 * Assumption: MySPs contains the sorted subprograms
 * */
Matcher::sp_iterator Matcher::slideToFile(StringRef fname)
{
  if (!processed) {
    errs() << "Warning: Matcher hasn't processed module\n";
    return sp_end();
  }
  sp_iterator I = sp_begin(), E = sp_end();

  while(I != E) {
    std::string debugname;
    if (I->filename.size() > 0 && I->filename[0] == '/')
      debugname = I->filename;
    else
      debugname = I->directory + "/" + I->filename;
    if (endswith(debugname.c_str(), patchname)) {
      break;
    }
    I++;
  }
  if (I == E)
    errs() << "Warning: no matching file(" << patchname << ") was found in the CU\n";
  return I;
}
Example #5
0
/** A progressive method to match the function(s) in a given scope.
 *  When there are more than one function in the scope, the first function
 *  will be returned and scope's beginning is *modified* to the end of this 
 *  returned function so that the caller could perform a loop of call until
 *  matchFunction return NULL;
 *
 *
 *  Note: finder.processModule(M) should be called before the first call of matchFunction.
 *
 * **/
Function * Matcher::matchFunction(sp_iterator & I, Scope &scope, bool & multiple)
{
  if (!initialized) {
    errs() << "Matcher is not initialized\n";
    return NULL;
  }
  // hit the boundary
  if (scope.end < scope.begin) {
    return NULL;
  }
  /** Off-the-shelf SP finder **/
  sp_iterator E = sp_end();
  while (I != E) {
    if (strlen(patchname) != 0) {
      std::string debugname = I->directory + "/" + I->filename;
      if (I->filename.size() > 0 && I->filename[0] == '/')
        debugname = I->filename;
      else
        debugname = I->directory + "/" + I->filename;
      if (!endswith(debugname.c_str(), patchname)) {
        errs() << "Warning: Reaching the end of " << patchname << " in current CU\n";
        return NULL;
      }
    }
    if (I->lastline == 0) {
      if (I + 1 == E)
        return I->function; // It's tricky to return I here. Maybe NULL is better
      // Line number is guaranteed to be positive, no need to check overflow here.
      if (I->linenumber == (I + 1)->linenumber) {
        errs() << "Warning two functions overlap: ";
        if (I->function && (I + 1)->function) {
          errs() << I->function->getName() << ", ";
          errs() << (I + 1)->function->getName();
        }
        errs() << "\n";
        I->lastline = (I + 1)->linenumber;
      }
      else
        I->lastline = (I + 1)->linenumber - 1;             
      if (I->lastline < I->linenumber) {
        errs() << "Bad things happened in " << patchname << ":" << scope << ", " <<
           I->lastline << "," << I->linenumber << "\n";
        assert(false); // Unless the two are modifying the same line.
      }
    }
    // For boundary case, we only break if that function is one line function.
    if (I->lastline > scope.begin || (I->lastline == scope.begin && I->lastline == I->linenumber))
      break;
    I++;
  }
  if (I == E)
    return NULL;

  //
  //                 |  f1   |        Cases of scope: 
  //  f1.lastline -> |_______|      (1)  (2)  (3)  (4)  (5)
  //                 +       +       ^    ^              ^
  //                 +  GAP  +       |    |              |
  //                 +       +       v    |              |
  // f2.linenumber-> ---------            |              |
  //                 |       |            v    ^    ^    |
  //                 |  f2   |                 |    |    |
  //  f2.lastline -> |_______|                 v    |    |
  //                 +       +                      |    |
  //                    ...                         v    v
  //

  // Case (1)
  if (I->linenumber > scope.end || (I->linenumber == scope.end && I->lastline > I->linenumber))
    return NULL;
  if (I->lastline < scope.end) { // Case (4), (5)
    scope.begin = I->lastline + 1;  // adjust beginning to next
    multiple = true;
  }
  multiple = false;
  return I->function; 
}
Example #6
0
errstat
sp_commit()
{
    struct sp_table *st;
    struct sp_save  *firstmod;
    objnum  obj;
    errstat err;
    
    /* When we get an error writing to the (probably local) bulletsvr,
     * we can do nothing but panic().  We cannot abort the transaction
     * because the other members will (presumably?) not have this problem
     * and hence have accepted the modification.
     */

    /* First see if we have multiple modifications as a result of the last
     * command. (This may happen as a result of sp_install()).
     * If so, we must use the intentions module rather than the modlist module
     * in order to guarantee atomicity.
     */
    st = sp_first_update();
    firstmod = (st != NULL) ? st->st_dir->sd_mods : NULL;

    if ((firstmod != NULL && firstmod->ss_next == NULL) /* just 1 mod */
	&& (st->st_dir->sd_update == NULL)		/* just 1 dir */)
    {
	obj = st - _sp_table;

	assert(sp_in_use(st));

	if (st->st_flags & SF_DESTROYING) {
	    MON_EVENT("destroying dir");
	    (void) remove_dir(obj);
	} else {
	    /* Note: we don't increase the current seqno of the directory
	     * itself, but use as the new seqnr the (already incremented)
	     * *global* sequence number.
	     * This avoids the possibility of having different incarnations
	     * of the same directory at the same time.
	     */
	    get_global_seqno(&st->st_dir->sd_seq_no);

	    err = ml_store(obj);
	    if (err != STD_OK && err != STD_NOSPACE) {
		/* Command not handled by modlist module, or no space in the
		 * modlist itself, or not enough memory.
		 */
		if (!ml_in_use()) {
		    /* Try to modify it, when possible and efficient.
		     * Otherwise write it out as a whole.
		     */
		    err = write_new_dir(obj, 1);
		} else {
		    /* Write it as a whole and remove it from the mod list */
		    err = ml_write_dir(obj);
		}
	    }

	    switch (err) {
	    case STD_OK:
		sp_free_mods(st);
		break;

	    case STD_NOSPACE:
		/* The directory would become to big.  This error should be
		 * consistent to all members, because they have the same
		 * data and use the same buffer sizes.
		 */
		scream("dir %ld would become too big", (long) obj); 
		sp_abort();	/* undoes the modification */
		return err;

	    default:
		/* must panic; see above */
		panic("sp_commit: cannot write dir %ld (%s)",
		      (long) obj, err_why(err));
	    }
	}
    } else {
	/* There are multiple updates or no updates at all */
	capability curcaps[NBULLETS];
	capability newcaps[NBULLETS];
	capability filesvrs[NBULLETS];
	struct sp_table *next_st;
	int nintents, avail;

	/* First make sure we have room for all of the intentions. */
	avail = intent_avail();
	nintents = 0;
	for (st = sp_first_update(); st != NULL; st = sp_next_update()) {
	    nintents++;
	}
	if (nintents > avail) {
	    scream("too many intentions: %d (max %d)", nintents, avail);
	    MON_EVENT("too many intentions");
	    sp_abort();
	    return STD_NOSPACE;
	}

	fsvr_get_svrs(filesvrs, NBULLETS);

	for (st = sp_first_update(); st != NULL; st = next_st ) {
	    next_st = sp_next_update();
	    obj = st - _sp_table;

	    /* Add an updated version of this dir to the intentions list.
	     * All dirs for which we have modifications should be in memory:
	     */
	    assert(sp_in_use(st));
	    assert(in_cache(obj));
    
	    /* Note: all directories modified in as a result of the current
	     * modification get the same seqno!
	     */
	    get_global_seqno(&st->st_dir->sd_seq_no);

	    if (!ml_in_use()) {
		/* Try to modify it, when possible and efficient.
		 * Otherwise write it out as a whole.
		 */
		get_dir_caps(obj, curcaps);
		err = dirf_modify(obj, NBULLETS, curcaps, newcaps, filesvrs);
	    } else {
		err = dirf_write(obj, NBULLETS, newcaps, filesvrs);
	    }

	    switch (err) {
	    case STD_OK:
		/* Put the new cap(s) in the intentions list.  Don't install
		 * them in the supertable yet: that'll be done after we have
		 * written the intention.  It'll also give us the opportunity
		 * to destroy the old versions afterwards.
		 */
		intent_add(obj, newcaps);
		MON_EVENT("added intention");
		break;

	    case STD_NOSPACE:
		/* The directory would become to big.  This error should be
		 * consistent to all members, because they have the same
		 * data and use the same buffer sizes.
		 * Remove the intentions and let the transaction fail.
		 */
		intent_undo();
		scream("dir %ld would become too big", (long) obj); 
		sp_abort();	/* undoes the modifications */
		return err;

	    default:	    /* must panic; see above */
		panic("sp_commit: cannot write dir %ld (%s)",
		      (long) obj, err_why(err));
	    }
	}

	if (nintents > 0) {
	    /* Write the intentions created to disk */
	    super_store_intents();

	    /* Install the modified directories in the super table and remove
	     * the intention again.  If we happen to crash between storing the
	     * intention and executing it, we'll complete it the next time
	     * during recovery.
	     */
	    intent_make_permanent();
	    MON_EVENT("executed intention");
	}
    }

    sp_clear_updates();
    sp_end();
    return STD_OK;
}