Example #1
0
int main(int argc, char **argv) {
    if (argc < 3) {
        std::cerr << "Please provide an input file and a page size." << std::endl;
        return -1;
    }
    std::string input(argv[1]);
    
    int page_size = std::stoi(argv[2]);
    auto words = get_words(input);
    std::vector<int> dyn(words.size(), -1),
        solution(words.size(), -1);
    justify_text(page_size, words, solution, dyn, 0);
    print_justified_text(words, page_size, solution);
    return 0;
}
Example #2
0
void Leapfrog::applyPeriodicCorrections(const shared_ptr<Node>& node, const Vector3r& linAccel){
	DemData& dyn(node->getData<DemData>());
	if (homoDeform==Cell::HOMO_VEL || homoDeform==Cell::HOMO_VEL_2ND) {
		// update velocity reflecting changes in the macroscopic velocity field, making the problem homothetic.
		//NOTE : if the velocity is updated before moving the body, it means the current gradV (i.e. before integration in cell->integrateAndUpdate) will be effective for the current time-step. Is it correct? If not, this velocity update can be moved just after "pos += vel*dt", meaning the current velocity impulse will be applied at next iteration, after the contact law. (All this assuming the ordering is resetForces->integrateAndUpdate->contactLaw->PeriCompressor->NewtonsLaw. Any other might fool us.)
		//NOTE : dVel defined without wraping the coordinates means bodies out of the (0,0,0) period can move realy fast. It has to be compensated properly in the definition of relative velocities (see Ig2 functors and contact laws).
		//This is the convective term, appearing in the time derivation of Cundall/Thornton expression (dx/dt=gradV*pos -> d²x/dt²=dGradV/dt+gradV*vel), negligible in many cases but not for high speed large deformations (gaz or turbulent flow).
		if (homoDeform==Cell::HOMO_VEL_2ND) dyn.vel+=midGradV*(dyn.vel-(dt/2.)*linAccel)*dt;
		//In all cases, reflect macroscopic (periodic cell) acceleration in the velocity. This is the dominant term in the update in most cases
		dyn.vel+=dGradV*node->pos;
	} else if (homoDeform==Cell::HOMO_POS){
		node->pos+=scene->cell->nextGradV*node->pos*dt;
	}
	/* should likewise apply angular velocity due to gradV spin, but this has never been done and contact laws don't handle that either */
}
    ExecuterWallBall(const vd::ExecutiveInit& init,
                     const vd::InitEventList& events)
    : vd::Executive(init, events),mWallNumbers(0),mBallNumbers(0)
    {
        mView = "view1";

        vp::Dynamic dyn("dyn_ball");
        dyn.setPackage("vle.extension.mas");
        dyn.setLibrary("BallG");
        dynamics().add(dyn);

        vp::Dynamic dynw("dyn_wall");
        dynw.setPackage("vle.extension.mas");
        dynw.setLibrary("WallG");
        dynamics().add(dynw);
    }
Example #4
0
void Geometry::upload(std::set<Buffers> dynamicAccess) {
	std::set<Buffers> dyn(dynamicAccess);
	if (m_hasDataVertices) {
		uploadVertices((dyn.find(VERTICES) == dyn.end()) ? STATIC_ACCESS : DYNAMIC_ACCESS);
	}
	if (m_hasDataNormals) {
		uploadNormals((dyn.find(NORMALS) == dyn.end()) ? STATIC_ACCESS : DYNAMIC_ACCESS);
	}
	if (m_hasDataColors) {
		uploadColors((dyn.find(COLORS) == dyn.end()) ? STATIC_ACCESS : DYNAMIC_ACCESS);
	}
	if (m_hasDataIndices) {
		uploadIndices((dyn.find(INDICES) == dyn.end()) ? STATIC_ACCESS : DYNAMIC_ACCESS);
	}
	if (m_hasTexCoords) {
		uploadTexCoords((dyn.find(TEXCOORDS) == dyn.end()) ? STATIC_ACCESS : DYNAMIC_ACCESS);
	}
}
Example #5
0
void Leapfrog::leapfrogAsphericalRotate(const shared_ptr<Node>& node, const Vector3r& M){
	Quaternionr& ori(node->ori); DemData& dyn(node->getData<DemData>());
	Vector3r& angMom(dyn.angMom);	Vector3r& angVel(dyn.angVel);	const Vector3r& inertia(dyn.inertia);
	// initialize angular momentum; it is in local coordinates, therefore angVel must be rotated
	if(isnan(angMom.minCoeff())){
		angMom=dyn.inertia.asDiagonal()*node->ori.conjugate()*dyn.angVel;
	}

	Matrix3r A=ori.conjugate().toRotationMatrix(); // rotation matrix from global to local r.f.
	const Vector3r l_n = angMom + dt/2 * M; // global angular momentum at time n
	const Vector3r l_b_n = A*l_n; // local angular momentum at time n
	const Vector3r angVel_b_n = (l_b_n.array()/inertia.array()).matrix(); // local angular velocity at time n
	const Quaternionr dotQ_n=DotQ(angVel_b_n,ori); // dQ/dt at time n
	const Quaternionr Q_half = ori + dt/2 * dotQ_n; // Q at time n+1/2
	angMom+=dt*M; // global angular momentum at time n+1/2
	const Vector3r l_b_half = A*angMom; // local angular momentum at time n+1/2
	Vector3r angVel_b_half = (l_b_half.array()/inertia.array()).matrix(); // local angular velocity at time n+1/2
	const Quaternionr dotQ_half=DotQ(angVel_b_half,Q_half); // dQ/dt at time n+1/2
	ori=ori+dt*dotQ_half; // Q at time n+1
	angVel=ori*angVel_b_half; // global angular velocity at time n+1/2

	ori.normalize();
}
Example #6
0
bool HostAndPort::isSelf() const {

    if( dyn() ) {
        MONGO_LOG(2) << "isSelf " << _dynName << ' ' << dynHostMyName() << endl;
        return dynHostMyName() == _dynName;
    }

    int _p = port();
    int p = _p == -1 ? CmdLine::DefaultDBPort : _p;

    if( p != cmdLine.port ) {
        // shortcut - ports have to match at the very least
        return false;
    }

    string host = str::stream() << this->host() << ":" << p;

    {
        // check cache for this host
        // debatably something _could_ change, but I'm not sure right now (erh 10/14/2010)
        scoped_lock lk( isSelfCommand._cacheLock );
        map<string,bool>::const_iterator i = isSelfCommand._cache.find( host );
        if ( i != isSelfCommand._cache.end() )
            return i->second;
    }

#if !defined(_WIN32) && !defined(__sunos__)
    // on linux and os x we can do a quick check for an ip match

    const vector<string> myaddrs = getMyAddrs();
    const vector<string> addrs = getAllIPs(_host);

    for (vector<string>::const_iterator i=myaddrs.begin(), iend=myaddrs.end(); i!=iend; ++i) {
        for (vector<string>::const_iterator j=addrs.begin(), jend=addrs.end(); j!=jend; ++j) {
            string a = *i;
            string b = *j;

            if ( a == b ||
                    ( str::startsWith( a , "127." ) && str::startsWith( b , "127." ) )  // 127. is all loopback
               ) {

                // add to cache
                scoped_lock lk( isSelfCommand._cacheLock );
                isSelfCommand._cache[host] = true;
                return true;
            }
        }
    }

#endif

    if ( ! Listener::getTimeTracker() ) {
        // this ensures we are actually running a server
        // this may return true later, so may want to retry
        return false;
    }

    try {
        isSelfCommand.init();
        DBClientConnection conn;
        string errmsg;
        if ( ! conn.connect( host , errmsg ) ) {
            // should this go in the cache?
            return false;
        }

        if (!noauth && cmdLine.keyFile &&
                !conn.auth("local", internalSecurity.user, internalSecurity.pwd, errmsg, false)) {
            return false;
        }

        BSONObj out;
        bool ok = conn.simpleCommand( "admin" , &out , "_isSelf" );
        bool me = ok && out["id"].type() == jstOID && isSelfCommand._id == out["id"].OID();

        // add to cache
        scoped_lock lk( isSelfCommand._cacheLock );
        isSelfCommand._cache[host] = me;

        return me;
    }
    catch ( std::exception& e ) {
        warning() << "could't check isSelf (" << host << ") " << e.what() << endl;
    }

    return false;
}
Example #7
0
void Leapfrog::leapfrogTranslate(const shared_ptr<Node>& node){
	DemData& dyn(node->getData<DemData>());
	node->pos+=dyn.vel*dt;
}
Example #8
0
void Leapfrog::run(){
	if(!reset && !_forceResetChecked){
		shared_ptr<ForceResetter> resetter;
		for(const auto& e: scene->engines){ resetter=dynamic_pointer_cast<ForceResetter>(e); if(resetter) break; }
		if(!resetter) LOG_WARN("Leapfrog.reset==False and no ForceResetter in Scene.engines! Are you sure this is ok? (proceeding)");
		_forceResetChecked=true;
	}
	#ifdef DUMP_INTEGRATOR
		cerr<<std::setprecision(17);
	#endif
	homoDeform=(scene->isPeriodic ? scene->cell->homoDeform : -1); // -1 for aperiodic simulations
	dGradV=scene->cell->nextGradV-scene->cell->gradV;
	midGradV=.5*(scene->cell->gradV+scene->cell->nextGradV);
	//cerr<<"gradV\n"<<scene->cell->gradV<<"\nnextGradV\n"<<scene->cell->nextGradV<<endl;
	dt=scene->dt;
	if(homoDeform==Cell::HOMO_GRADV2){
		const Matrix3r& pprevL(scene->cell->gradV); const Matrix3r& nnextL(scene->cell->nextGradV);
		ImLL4hInv=(Matrix3r::Identity()-dt*(nnextL+pprevL)/4.).inverse();
		IpLL4h   = Matrix3r::Identity()+dt*(nnextL+pprevL)/4.;
		LmL=(nnextL-pprevL); 
		// https://answers.launchpad.net/yade/+question/247806 : am I really sure about the .5? no, I am not!!
		// difference of "spin" (angVel) vectors, which are duals of spin tensor
		deltaSpinVec=-.5*leviCivita((.5*(pprevL-pprevL.transpose())).eval())+.5*leviCivita((.5*(nnextL-nnextL.transpose())).eval());
	}

	const bool isPeriodic(scene->isPeriodic);
	/* don't evaluate energy in the first step with non-zero velocity gradient, since kinetic energy will be way off
	   (meanfield velocity has not yet been applied) */
	const bool reallyTrackEnergy=(scene->trackEnergy&&(!isPeriodic || scene->step>0 || scene->cell->gradV==Matrix3r::Identity()));

	DemField* dem=dynamic_cast<DemField*>(field.get());
	assert(dem);
	bool hasGravity(dem->gravity!=Vector3r::Zero());

	if(dem->nodes.empty()){
		Master::instance().checkApi(/*minApi*/10101,"DemField.nodes is empty; woo.dem.Leapfrog no longer calls DemField.collectNodes() automatically.",/*pyWarn*/false); // can happen in bg thread?
	}

	size_t size=dem->nodes.size();
	const auto& nodes=dem->nodes;
	#ifdef WOO_OPENMP
		#pragma omp parallel for schedule(guided)
	#endif
	for(size_t i=0; i<size; i++){
		const shared_ptr<Node>& node=nodes[i];
		assert(node->hasData<DemData>()); // checked in DemField::selfTest
		DemData& dyn(node->getData<DemData>());
		// handle clumps
		if(dyn.isClumped()) continue; // those particles are integrated via the clump's master node
		bool isClump=dyn.isClump();
		bool damp=(damping!=0. && !dyn.isDampingSkip());
		// useless to compute node force if the value will not be used at all
		if(isClump && (!dyn.isBlockedAll() || (dyn.impose && (dyn.impose->what & Impose::READ_FORCE)))){
			// accumulates to existing values of dyn.force, dy.torque (normally zero)
			ClumpData::forceTorqueFromMembers(node,dyn.force,dyn.torque);
		}
		Vector3r& f=dyn.force;
		Vector3r& t=dyn.torque;

		if(unlikely(reallyTrackEnergy)){
			if(damp) doDampingDissipation(node);
			if(hasGravity) doGravityWork(dyn,*dem);
		}
			

		// fluctuation velocity does not contain meanfield velocity in periodic boundaries
		// in aperiodic boundaries, it is equal to absolute velocity
		// it is only computed later, since acceleration is needed to be known already
		Vector3r pprevFluctVel, pprevFluctAngVel;

		// whether to use aspherical rotation integration for this body; for no accelerations, spherical integrator is "exact" (and faster)
		bool useAspherical=dyn.useAsphericalLeapfrog(); // shorthand for (dyn.isAspherical() && !dyn.isBlockedAllRot())

		Vector3r linAccel(Vector3r::Zero()), angAccel(Vector3r::Zero());
		// for particles not totally blocked, compute accelerations; otherwise, the computations would be useless
		if (!dyn.isBlockedAll()) {
			linAccel=computeAccel(f,dyn.mass,dyn);
			// fluctuation velocities
			if(isPeriodic){
				pprevFluctVel=scene->cell->pprevFluctVel(node->pos,dyn.vel,dt);
				pprevFluctAngVel=scene->cell->pprevFluctAngVel(dyn.angVel);
			} else { pprevFluctVel=dyn.vel; pprevFluctAngVel=dyn.angVel; }
			// linear damping
			if(damp) nonviscDamp2nd(dt,f,pprevFluctVel,linAccel);
			// compute v(t+dt/2)
			if(homoDeform==Cell::HOMO_GRADV2) dyn.vel=ImLL4hInv*(LmL*node->pos+IpLL4h*dyn.vel+linAccel*dt);
			else dyn.vel+=dt*linAccel;  // correction for this case is below
			// angular acceleration
			if(dyn.inertia!=Vector3r::Zero()){
				if(!useAspherical){ // spherical integrator, uses angular velocity
					angAccel=computeAngAccel(t,dyn.inertia,dyn);
					if(damp) nonviscDamp2nd(dt,t,pprevFluctAngVel,angAccel);
					dyn.angVel+=dt*angAccel;
					if(homoDeform==Cell::HOMO_GRADV2) dyn.angVel-=deltaSpinVec;
				} else { // uses torque
					for(int i=0; i<3; i++) if(dyn.isBlockedAxisDOF(i,true)) t[i]=0; // block DOFs here
					if(damp) nonviscDamp1st(t,pprevFluctAngVel);
				}
			}
			// in case velocity is imposed, it must be re-applied to cancel effects of forces
			// this is not necessary if all DOFs are blocked, since then velocity is not modified
			if(dyn.impose && (dyn.impose->what & Impose::VELOCITY)) dyn.impose->velocity(scene,node);
		}
		else{
			// fixed particle, with gradV2: velocity correction, without acceleration
			if(homoDeform==Cell::HOMO_GRADV2) dyn.vel=ImLL4hInv*(LmL*node->pos+IpLL4h*dyn.vel);
		}
		/* adapt node velocity/position in (t+dt/2) to space gradV;	must be done before position update, so that particle follows */
		// this is for both fixed and free particles, without gradV2
		if(homoDeform>=0 && homoDeform!=Cell::HOMO_GRADV2) applyPeriodicCorrections(node,linAccel);

		// kinetic energy
		// accelerations are needed, therefore not evaluated earlier;
		if(unlikely(reallyTrackEnergy)) doKineticEnergy(node,pprevFluctVel,pprevFluctAngVel,linAccel,angAccel);


		// update positions from velocities
		leapfrogTranslate(node);
		#ifdef DUMP_INTEGRATOR
			if(!dyn.isBlockedAll()) cerr<<", posNew="<<node->pos<<endl;
		#endif
		// update orientation from angular velocity (or torque, for aspherical integrator)
		if(!useAspherical) leapfrogSphericalRotate(node);
		else {
			if(dyn.inertia==Vector3r::Zero()) throw std::runtime_error("Leapfrog::run: DemField.nodes["+to_string(i)+"].den.inertia==(0,0,0), but the node wants to use aspherical integrator. Aspherical integrator is selected for non-spherical particles which have at least one rotational DOF free.");
			if(!isPeriodic) leapfrogAsphericalRotate(node,t);
			else{
				// FIXME: add fake torque from rotating space or modify angMom or angVel
				leapfrogAsphericalRotate(node,t); //-dyn.inertia.asDiagonal()*node->ori.conjugate()*deltaSpinVec/dt*2);
			}
		}

		// read back forces from the node (before they are reset)
		if(dyn.impose && (dyn.impose->what & Impose::READ_FORCE)) dyn.impose->readForce(scene,node);

		if(reset){
			// apply gravity only to the clump itself (not to the nodes later, in CLumpData::applyToMembers)
			dyn.force=(hasGravity && !dyn.isGravitySkip())?(dyn.mass*dem->gravity).eval():Vector3r::Zero();
			dyn.torque=Vector3r::Zero();
			if(dyn.impose && (dyn.impose->what & Impose::FORCE)) dyn.impose->force(scene,node);
		}

		// if something is imposed, apply it here
		if(dyn.impose && (dyn.impose->what & Impose::VELOCITY)) dyn.impose->velocity(scene,node);

		// for clumps, update positions/orientations of members as well
		// (gravity already applied to the clump node itself, pass zero here! */
		if(isClump) ClumpData::applyToMembers(node,/*resetForceTorque*/reset);
	}
	// if(isPeriodic) prevVelGrad=scene->cell->velGrad;
}
bool SharedLibrary::Load(const char* full_path,
                         size_t load_address,
                         size_t file_offset,
                         Error* error) {
  // First, record the path.
  LOG("%s: full path '%s'\n", __FUNCTION__, full_path);

  size_t full_path_len = strlen(full_path);
  if (full_path_len >= sizeof(full_path_)) {
    error->Format("Path too long: %s", full_path);
    return false;
  }

  strlcpy(full_path_, full_path, sizeof(full_path_));
  base_name_ = GetBaseNamePtr(full_path_);

  // Load the ELF binary in memory.
  LOG("%s: Loading ELF segments for %s\n", __FUNCTION__, base_name_);

  {
    ElfLoader loader;
    if (!loader.LoadAt(full_path_, file_offset, load_address, error)) {
      return false;
    }

    if (!view_.InitUnmapped(loader.load_start(),
                            loader.loaded_phdr(),
                            loader.phdr_count(),
                            error)) {
      return false;
    }

    if (!symbols_.Init(&view_)) {
      *error = "Missing or malformed symbol table";
      return false;
    }
  }

  if (phdr_table_get_relro_info(view_.phdr(),
                                view_.phdr_count(),
                                view_.load_bias(),
                                &relro_start_,
                                &relro_size_) < 0) {
    relro_start_ = 0;
    relro_size_ = 0;
  }

#ifdef __arm__
  LOG("%s: Extracting ARM.exidx table for %s\n", __FUNCTION__, base_name_);
  (void)phdr_table_get_arm_exidx(
      phdr(), phdr_count(), load_bias(), &arm_exidx_, &arm_exidx_count_);
#endif

  LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_);
  ElfView::DynamicIterator dyn(&view_);
  for (; dyn.HasNext(); dyn.GetNext()) {
    ELF::Addr dyn_value = dyn.GetValue();
    uintptr_t dyn_addr = dyn.GetAddress(load_bias());
    switch (dyn.GetTag()) {
      case DT_DEBUG:
        if (view_.dynamic_flags() & PF_W) {
          *dyn.GetValuePointer() =
              reinterpret_cast<uintptr_t>(Globals::GetRDebug()->GetAddress());
        }
        break;
      case DT_INIT:
        LOG("  DT_INIT addr=%p\n", dyn_addr);
        init_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
        break;
      case DT_FINI:
        LOG("  DT_FINI addr=%p\n", dyn_addr);
        fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
        break;
      case DT_INIT_ARRAY:
        LOG("  DT_INIT_ARRAY addr=%p\n", dyn_addr);
        init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
        break;
      case DT_INIT_ARRAYSZ:
        init_array_count_ = dyn_value / sizeof(ELF::Addr);
        LOG("  DT_INIT_ARRAYSZ value=%p count=%p\n",
            dyn_value,
            init_array_count_);
        break;
      case DT_FINI_ARRAY:
        LOG("  DT_FINI_ARRAY addr=%p\n", dyn_addr);
        fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
        break;
      case DT_FINI_ARRAYSZ:
        fini_array_count_ = dyn_value / sizeof(ELF::Addr);
        LOG("  DT_FINI_ARRAYSZ value=%p count=%p\n",
            dyn_value,
            fini_array_count_);
        break;
      case DT_PREINIT_ARRAY:
        LOG("  DT_PREINIT_ARRAY addr=%p\n", dyn_addr);
        preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
        break;
      case DT_PREINIT_ARRAYSZ:
        preinit_array_count_ = dyn_value / sizeof(ELF::Addr);
        LOG("  DT_PREINIT_ARRAYSZ value=%p count=%p\n",
            dyn_value,
            preinit_array_count_);
        break;
      case DT_SYMBOLIC:
        LOG("  DT_SYMBOLIC\n");
        has_DT_SYMBOLIC_ = true;
        break;
      case DT_FLAGS:
        if (dyn_value & DF_SYMBOLIC)
          has_DT_SYMBOLIC_ = true;
        break;
#if defined(__mips__)
      case DT_MIPS_RLD_MAP:
        *dyn.GetValuePointer() =
            reinterpret_cast<ELF::Addr>(Globals::GetRDebug()->GetAddress());
        break;
#endif
      default:
        ;
    }
  }

  LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_);
  return true;
}
bool ElfRelocations::Init(const ElfView* view, Error* error) {
  // Save these for later.
  phdr_ = view->phdr();
  phdr_count_ = view->phdr_count();
  load_bias_ = view->load_bias();

  // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ
  // then we require DT_PLTREL to agree.
  bool has_rela_relocations = false;
  bool has_rel_relocations = false;

  // Parse the dynamic table.
  ElfView::DynamicIterator dyn(view);
  for (; dyn.HasNext(); dyn.GetNext()) {
    ELF::Addr dyn_value = dyn.GetValue();
    uintptr_t dyn_addr = dyn.GetAddress(view->load_bias());

    const ELF::Addr tag = dyn.GetTag();
    switch (tag) {
      case DT_PLTREL:
        RLOG("  DT_PLTREL value=%d\n", dyn_value);
        if (dyn_value != DT_REL && dyn_value != DT_RELA) {
          *error = "Invalid DT_PLTREL value in dynamic section";
          return false;
        }
        relocations_type_ = dyn_value;
        break;
      case DT_JMPREL:
        RLOG("  DT_JMPREL addr=%p\n", dyn_addr);
        plt_relocations_ = dyn_addr;
        break;
      case DT_PLTRELSZ:
        plt_relocations_size_ = dyn_value;
        RLOG("  DT_PLTRELSZ size=%d\n", dyn_value);
        break;
      case DT_RELA:
      case DT_REL:
        RLOG("  %s addr=%p\n",
             (tag == DT_RELA) ? "DT_RELA" : "DT_REL",
             dyn_addr);
        if (relocations_) {
          *error = "Unsupported DT_RELA/DT_REL combination in dynamic section";
          return false;
        }
        relocations_ = dyn_addr;
        if (tag == DT_RELA)
          has_rela_relocations = true;
        else
          has_rel_relocations = true;
        break;
      case DT_RELASZ:
      case DT_RELSZ:
        RLOG("  %s size=%d\n",
             (tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ",
             dyn_addr);
        if (relocations_size_) {
          *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section";
          return false;
        }
        relocations_size_ = dyn_value;
        if (tag == DT_RELASZ)
          has_rela_relocations = true;
        else
          has_rel_relocations = true;
        break;
      case DT_ANDROID_RELA:
      case DT_ANDROID_REL:
        RLOG("  %s addr=%p\n",
             (tag == DT_ANDROID_RELA) ? "DT_ANDROID_RELA" : "DT_ANDROID_REL",
             dyn_addr);
        if (android_relocations_) {
          *error = "Unsupported DT_ANDROID_RELA/DT_ANDROID_REL "
                   "combination in dynamic section";
          return false;
        }
        android_relocations_ = reinterpret_cast<uint8_t*>(dyn_addr);
        if (tag == DT_ANDROID_RELA)
          has_rela_relocations = true;
        else
          has_rel_relocations = true;
        break;
      case DT_ANDROID_RELASZ:
      case DT_ANDROID_RELSZ:
        RLOG("  %s size=%d\n",
             (tag == DT_ANDROID_RELASZ)
                 ? "DT_ANDROID_RELASZ" : "DT_ANDROID_RELSZ", dyn_addr);
        if (android_relocations_size_) {
          *error = "Unsupported DT_ANDROID_RELASZ/DT_ANDROID_RELSZ "
                   "combination in dyn section";
          return false;
        }
        android_relocations_size_ = dyn_value;
        if (tag == DT_ANDROID_RELASZ)
          has_rela_relocations = true;
        else
          has_rel_relocations = true;
        break;
      case DT_PLTGOT:
        // Only used on MIPS currently. Could also be used on other platforms
        // when lazy binding (i.e. RTLD_LAZY) is implemented.
        RLOG("  DT_PLTGOT addr=%p\n", dyn_addr);
        plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr);
        break;
      case DT_TEXTREL:
        RLOG("  DT_TEXTREL\n");
        has_text_relocations_ = true;
        break;
      case DT_SYMBOLIC:
        RLOG("  DT_SYMBOLIC\n");
        has_symbolic_ = true;
        break;
      case DT_FLAGS:
        if (dyn_value & DF_TEXTREL)
          has_text_relocations_ = true;
        if (dyn_value & DF_SYMBOLIC)
          has_symbolic_ = true;
        RLOG("  DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
             has_text_relocations_ ? "true" : "false",
             has_symbolic_ ? "true" : "false");
        break;
#if defined(__mips__)
      case DT_MIPS_SYMTABNO:
        RLOG("  DT_MIPS_SYMTABNO value=%d\n", dyn_value);
        mips_symtab_count_ = dyn_value;
        break;

      case DT_MIPS_LOCAL_GOTNO:
        RLOG("  DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value);
        mips_local_got_count_ = dyn_value;
        break;

      case DT_MIPS_GOTSYM:
        RLOG("  DT_MIPS_GOTSYM value=%d\n", dyn_value);
        mips_gotsym_ = dyn_value;
        break;
#endif
      default:
        ;
    }
  }

  if (has_rel_relocations && has_rela_relocations) {
    *error = "Combining relocations with and without addends is not "
             "currently supported";
    return false;
  }

  // If DT_PLTREL did not explicitly assign relocations_type_, set it
  // here based on the type of relocations found.
  if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) {
    if (has_rel_relocations)
      relocations_type_ = DT_REL;
    else if (has_rela_relocations)
      relocations_type_ = DT_RELA;
  }

  if (relocations_type_ == DT_REL && has_rela_relocations) {
    *error = "Found relocations with addends in dyn section, "
             "but DT_PLTREL is DT_REL";
    return false;
  }
  if (relocations_type_ == DT_RELA && has_rel_relocations) {
    *error = "Found relocations without addends in dyn section, "
             "but DT_PLTREL is DT_RELA";
    return false;
  }

  return true;
}