status_t
BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint,
	bool enabled)
{
	TRACE_CONTROL("BreakpointManager::InstallUserBreakpoint(%p, %d)\n",
		userBreakpoint, enabled);

	AutoLocker<BLocker> installLocker(fLock);
	AutoLocker<Team> teamLocker(fTeam);

	bool oldEnabled = userBreakpoint->IsEnabled();
	if (userBreakpoint->IsValid() && enabled == oldEnabled) {
		TRACE_CONTROL("  user breakpoint already valid and with same enabled "
			"state\n");
		return B_OK;
	}

	// get/create the breakpoints for all instances
	TRACE_CONTROL("  creating breakpoints for breakpoint instances\n");

	status_t error = B_OK;
	for (int32 i = 0;
		UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {

		TRACE_CONTROL("    breakpoint instance %p\n", instance);

		if (instance->GetBreakpoint() != NULL) {
			TRACE_CONTROL("    -> already has breakpoint\n");
			continue;
		}

		target_addr_t address = instance->Address();
		Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
		if (breakpoint == NULL) {
			TRACE_CONTROL("    -> no breakpoint at that address yet\n");

			Image* image = fTeam->ImageByAddress(address);
			if (image == NULL) {
				TRACE_CONTROL("    -> no image at that address\n");
				error = B_BAD_ADDRESS;
				break;
			}

			breakpoint = new(std::nothrow) Breakpoint(image, address);
			if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) {
				delete breakpoint;
				error = B_NO_MEMORY;
				break;
			}
		}

		TRACE_CONTROL("    -> adding instance to breakpoint %p\n", breakpoint);

		breakpoint->AddUserBreakpoint(instance);
		instance->SetBreakpoint(breakpoint);
	}

	// If everything looks good so far mark the user breakpoint according to
	// its new state.
	if (error == B_OK)
		userBreakpoint->SetEnabled(enabled);

	// notify user breakpoint listeners
	if (error == B_OK)
		fTeam->NotifyUserBreakpointChanged(userBreakpoint);

	teamLocker.Unlock();

	// install/uninstall the breakpoints as needed
	TRACE_CONTROL("  updating breakpoints\n");

	if (error == B_OK) {
		for (int32 i = 0;
			UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
			i++) {
			TRACE_CONTROL("    breakpoint instance %p\n", instance);

			error = _UpdateBreakpointInstallation(instance->GetBreakpoint());
			if (error != B_OK)
				break;
		}
	}

	if (error == B_OK) {
		TRACE_CONTROL("  success, marking user breakpoint valid\n");

		// everything went fine -- mark the user breakpoint valid
		if (!userBreakpoint->IsValid()) {
			teamLocker.Lock();
			userBreakpoint->SetValid(true);
			userBreakpoint->AcquireReference();
			fTeam->AddUserBreakpoint(userBreakpoint);
			fTeam->NotifyUserBreakpointChanged(userBreakpoint);
				// notify again -- the breakpoint hadn't been added before
			teamLocker.Unlock();
		}
	} else {
		// something went wrong -- revert the situation
		TRACE_CONTROL("  error, reverting\n");

		teamLocker.Lock();
		userBreakpoint->SetEnabled(oldEnabled);
		teamLocker.Unlock();

		if (!oldEnabled || !userBreakpoint->IsValid()) {
			for (int32 i = 0;  UserBreakpointInstance* instance
					= userBreakpoint->InstanceAt(i);
				i++) {
				Breakpoint* breakpoint = instance->GetBreakpoint();
				if (breakpoint == NULL)
					continue;

				if (!userBreakpoint->IsValid()) {
					instance->SetBreakpoint(NULL);
					breakpoint->RemoveUserBreakpoint(instance);
				}

				_UpdateBreakpointInstallation(breakpoint);

				teamLocker.Lock();

				if (breakpoint->IsUnused())
					fTeam->RemoveBreakpoint(breakpoint);
				teamLocker.Unlock();
			}

			teamLocker.Lock();
			fTeam->NotifyUserBreakpointChanged(userBreakpoint);
			teamLocker.Unlock();
		}
	}

	installLocker.Unlock();

	return error;
}
void
BreakpointManager::_UpdateImageBreakpoints(Image* image, bool removeOnly)
{
	AutoLocker<BLocker> installLocker(fLock);
	AutoLocker<Team> teamLocker(fTeam);

	// remove obsolete user breakpoint instances
	BObjectList<Breakpoint> breakpointsToUpdate;
	for (UserBreakpointList::ConstIterator it
			= fTeam->UserBreakpoints().GetIterator();
		UserBreakpoint* userBreakpoint = it.Next();) {
		int32 instanceCount = userBreakpoint->CountInstances();
		for (int32 i = instanceCount - 1; i >= 0; i--) {
			UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
			Breakpoint* breakpoint = instance->GetBreakpoint();
			if (breakpoint == NULL || breakpoint->GetImage() != image)
				continue;

			userBreakpoint->RemoveInstanceAt(i);
			breakpoint->RemoveUserBreakpoint(instance);

			if (!breakpointsToUpdate.AddItem(breakpoint)) {
				_UpdateBreakpointInstallation(breakpoint);
				if (breakpoint->IsUnused())
					fTeam->RemoveBreakpoint(breakpoint);
			}

			delete instance;
		}
	}

	// update breakpoints
	teamLocker.Unlock();
	for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i);
			i++) {
		_UpdateBreakpointInstallation(breakpoint);
	}

	teamLocker.Lock();
	for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i);
			i++) {
		if (breakpoint->IsUnused())
			fTeam->RemoveBreakpoint(breakpoint);
	}

	// add breakpoint instances for function instances in the image (if we have
	// an image debug info)
	BObjectList<UserBreakpointInstance> newInstances;
	ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
	if (imageDebugInfo == NULL)
		return;

	for (UserBreakpointList::ConstIterator it
			= fTeam->UserBreakpoints().GetIterator();
		UserBreakpoint* userBreakpoint = it.Next();) {
		// get the function
		Function* function = fTeam->FunctionByID(
			userBreakpoint->Location().GetFunctionID());
		if (function == NULL)
			continue;

		const SourceLocation& sourceLocation
			= userBreakpoint->Location().GetSourceLocation();
		target_addr_t relativeAddress
			= userBreakpoint->Location().RelativeAddress();

		// iterate through the function instances
		for (FunctionInstanceList::ConstIterator it
				= function->Instances().GetIterator();
			FunctionInstance* functionInstance = it.Next();) {
			if (functionInstance->GetImageDebugInfo() != imageDebugInfo)
				continue;

			// get the breakpoint address for the instance
			target_addr_t instanceAddress = 0;
			if (functionInstance->SourceFile() != NULL) {
				// We have a source file, so get the address for the source
				// location.
				Statement* statement = NULL;
				FunctionDebugInfo* functionDebugInfo
					= functionInstance->GetFunctionDebugInfo();
				functionDebugInfo->GetSpecificImageDebugInfo()
					->GetStatementAtSourceLocation(functionDebugInfo,
						sourceLocation, statement);
				if (statement != NULL) {
					instanceAddress = statement->CoveringAddressRange().Start();
						// TODO: What about BreakpointAllowed()?
					statement->ReleaseReference();
					// TODO: Make sure we do hit the function in question!
				}
			}

			if (instanceAddress == 0) {
				// No source file (or we failed getting the statement), so try
				// to use the same relative address.
				if (relativeAddress > functionInstance->Size())
					continue;
				instanceAddress = functionInstance->Address() + relativeAddress;
					// TODO: Make sure it does at least hit an instruction!
			}

			// create the user breakpoint instance
			UserBreakpointInstance* instance = new(std::nothrow)
				UserBreakpointInstance(userBreakpoint, instanceAddress);
			if (instance == NULL || !newInstances.AddItem(instance)) {
				delete instance;
				continue;
			}

			if (!userBreakpoint->AddInstance(instance)) {
				newInstances.RemoveItemAt(newInstances.CountItems() - 1);
				delete instance;
			}

			// get/create the breakpoint for the address
			target_addr_t address = instance->Address();
			Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
			if (breakpoint == NULL) {
				breakpoint = new(std::nothrow) Breakpoint(image, address);
				if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) {
					delete breakpoint;
					break;
				}
			}

			breakpoint->AddUserBreakpoint(instance);
			instance->SetBreakpoint(breakpoint);
		}
	}

	// install the breakpoints for the new user breakpoint instances
	teamLocker.Unlock();
	for (int32 i = 0; UserBreakpointInstance* instance = newInstances.ItemAt(i);
			i++) {
		Breakpoint* breakpoint = instance->GetBreakpoint();
		if (breakpoint == NULL
			|| _UpdateBreakpointInstallation(breakpoint) != B_OK) {
			// something went wrong -- remove the instance
			teamLocker.Lock();

			instance->GetUserBreakpoint()->RemoveInstance(instance);
			if (breakpoint != NULL) {
				breakpoint->AddUserBreakpoint(instance);
				if (breakpoint->IsUnused())
					fTeam->RemoveBreakpoint(breakpoint);
			}

			teamLocker.Unlock();
		}
	}
}