Example #1
0
status_t
thread_debug_thread(void *arg)
{
	Tdebug_thead_param*	param = (Tdebug_thead_param*) arg;
	debug_thread(param->thread);
	delete param;
	return B_OK;
}
Example #2
0
static status_t
haiku_stop_thread(team_debug_info *teamDebugInfo, thread_id threadID)
{
	// check whether we know the thread
	status_t err;
	thread_event_closure threadEventClosure;

	thread_debug_info *threadInfo = haiku_find_thread(teamDebugInfo, threadID);
	if (!threadInfo)
		return B_BAD_THREAD_ID;

	// already stopped?
	if (threadInfo->stopped)
		return B_OK;

	// debug the thread
	err = debug_thread(threadID);
	if (err != B_OK) {
		TRACE(("haiku_stop_thread(): failed to debug thread %ld: %s\n",
			threadID, strerror(err)));
		return err;
	}

	// wait for the event to hit our port

	// TODO: debug_thread() doesn't guarantee that the thread will enter the
	// debug loop any time soon. E.g. a wait_for_thread() is (at the moment)
	// not interruptable, so we block here forever, if we already debug the
	// thread that is being waited for. We should probably limit the time
	// we're waiting, and return the info to the caller, which can then try
	// to deal with the situation in an appropriate way.

	// prepare closure for finding interesting events
	threadEventClosure.context = teamDebugInfo;
	threadEventClosure.thread = threadID;
	threadEventClosure.event = NULL;

	// find the first interesting queued event
	threadEventClosure.event = haiku_find_next_debug_event(
		&teamDebugInfo->events, haiku_thread_event_predicate,
		&threadEventClosure);

	// read all events pending on the port
	haiku_read_pending_debug_events(teamDebugInfo,
		(threadEventClosure.event == NULL), haiku_thread_event_predicate,
		&threadEventClosure);

	// We should check, whether we really got an event for the thread in
	// question, but the only possible other event is that the team has
	// been delete, which ends the game anyway.

	// TODO: That's actually not true. We also get messages when an add-on
	// has been loaded/unloaded, a signal arrives, or a thread calls the
	// debugger.

	return B_OK;
}
Example #3
0
static void
haiku_child_stop_inferior (void)
{
	status_t err;
	thread_id threadID = ptid_get_tid(inferior_ptid);

	TRACE(("haiku_child_stop_inferior()\n"));

	err = debug_thread(threadID);
	if (err != B_OK) {
		printf_unfiltered ("Failed to stop thread %ld: %s\n", threadID,
			strerror(err));
		return;
	}
}
status_t
LocalDebuggerInterface::StopThread(thread_id thread)
{
	return debug_thread(thread);
}
Example #5
0
static void
haiku_init_child_debugging (thread_id threadID, bool debugThread)
{
	thread_info threadInfo;
	status_t result;
	port_id nubPort;

	// get a thread info
	result = get_thread_info(threadID, &threadInfo);
	if (result != B_OK)
		error("Thread with ID %ld not found: %s", threadID, strerror(result));

	// init our team debug structure
	sTeamDebugInfo.team = threadInfo.team;
	sTeamDebugInfo.debugger_port = -1;
	sTeamDebugInfo.context.nub_port = -1;
	sTeamDebugInfo.context.reply_port = -1;
	sTeamDebugInfo.threads = NULL;
	sTeamDebugInfo.events.head = NULL;
	sTeamDebugInfo.events.tail = NULL;

	// create the debugger port
	sTeamDebugInfo.debugger_port = create_port(10, "gdb debug");
	if (sTeamDebugInfo.debugger_port < 0) {
		error("Failed to create debugger port: %s",
			strerror(sTeamDebugInfo.debugger_port));
	}

	// install ourselves as the team debugger
	nubPort = install_team_debugger(sTeamDebugInfo.team,
		sTeamDebugInfo.debugger_port);
	if (nubPort < 0) {
		error("Failed to install ourselves as debugger for team %ld: %s",
			sTeamDebugInfo.team, strerror(nubPort));
	}

	// get the nub thread
	{
		team_info teamInfo;
		result = get_team_info(sTeamDebugInfo.team, &teamInfo);
		if (result != B_OK) {
			error("Failed to get info for team %ld: %s\n",
				sTeamDebugInfo.team, strerror(result));
		}

		sTeamDebugInfo.nub_thread = teamInfo.debugger_nub_thread;
	}

	// init the debug context
	result = init_debug_context(&sTeamDebugInfo.context, sTeamDebugInfo.team,
		nubPort);
	if (result != B_OK) {
		error("Failed to init debug context for team %ld: %s\n",
			sTeamDebugInfo.team, strerror(result));
	}

	// start debugging the thread
	if (debugThread) {
		result = debug_thread(threadID);
		if (result != B_OK) {
			error("Failed to start debugging thread %ld: %s", threadID,
				strerror(result));
		}
	}

	// set the team debug flags
	{
		debug_nub_set_team_flags message;
		message.flags = B_TEAM_DEBUG_SIGNALS /*| B_TEAM_DEBUG_PRE_SYSCALL
			| B_TEAM_DEBUG_POST_SYSCALL*/ | B_TEAM_DEBUG_TEAM_CREATION
			| B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES;
			// TODO: We probably don't need all events

		haiku_send_debugger_message(&sTeamDebugInfo,
			B_DEBUG_MESSAGE_SET_TEAM_FLAGS, &message, sizeof(message), NULL, 0);
	}


	// the fun can start: push the target and init the rest
	push_target(sHaikuTarget);

	haiku_init_thread_list(&sTeamDebugInfo);
	haiku_init_image_list(&sTeamDebugInfo);

	disable_breakpoints_in_shlibs (1);

//	child_clear_solibs ();
		// TODO: Implement? Do we need this?

	clear_proceed_status ();
	init_wait_for_inferior ();

	target_terminal_init ();
	target_terminal_inferior ();
}
status_t
thread_debug_thread(void *arg)
{
	Tdebug_thead_param*	param = (Tdebug_thead_param*) arg;
#ifdef __HAIKU__
	debug_thread(param->thread);
#else	// !__HAIKU__
	thread_info	thinfo;
	get_thread_info(param->thread, &thinfo);
	char text[4096];
	sprintf(text, "db %d", int(param->thread));
	system(text);
	if (param->sem >= 0 && thinfo.state == B_THREAD_WAITING && param->sem
			== thinfo.sem) {
		snooze(1000000);
		get_thread_info(param->thread, &thinfo);
		if (thinfo.state == B_THREAD_WAITING
			&& param->sem == thinfo.sem
			&& param->totalTime == thinfo.user_time + thinfo.kernel_time) {
			// the thread has been waiting for this semaphore since the before
			// the alert, not doing anything... Let's push it out of there!
			sem_info sinfo;
			thread_info thinfo;
			info_pack infos;

			if (get_sem_info(param->sem, &sinfo) == B_OK
				&& get_thread_info(param->thread, &thinfo) == B_OK
				&& get_team_info(thinfo.team, &infos.team_info) == B_OK) {
				sprintf (text, "This thread is waiting for the "
					"semaphore called \"%s\". As long as it waits for this "
					"semaphore, you won't be able to debug that thread.\n",
						sinfo.name);
				if (sinfo.team == thinfo.team)
					strcat(text, "This semaphore belongs to the "
						"thread's team.\n\nShould I release this semaphore?\n");
				else {
					get_team_name_and_icon(infos);
					char moreText[1024];
					sprintf(moreText, "\nWARNING! This semaphore "
						"belongs to the team \"%s\"!\n\nShould I release this "
						"semaphore anyway?\n",
						infos.team_name);
					strcat(text, moreText);
				}

				BAlert* alert = new BAlert("", text, "Cancel", "Release",
						NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
				alert->SetShortcut(0, B_ESCAPE);
				if (alert->Go()) {
					get_thread_info (param->thread, &thinfo);
					if (thinfo.state == B_THREAD_WAITING && param->sem
							== thinfo.sem
						&& param->totalTime == thinfo.user_time
							+ thinfo.kernel_time)
						release_sem(param->sem);
					else {
						alert = new BAlert("", "The semaphore wasn't released, "
							"because it wasn't necessary anymore!",
							"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
						alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
						alert->Go();
					}
				}
			}
		}
	}
#endif	// !__HAIKU__
	delete param;
	return B_OK;
}
Example #7
0
static void
kerext_debug_process(void *args) {
	PROCESS							*prp;
	THREAD							*thp, *act = actives[KERNCPU];
	DEBUG							*dep;
	struct kerargs_debug_process	*kap = args;
	int								status;
	int								stopped;
	int								tid;

	if(!(prp = lookup_pid(kap->pid))) {
		kererr(act, ESRCH);
		return;
	}

	dep = prp->debugger;

	if(kap->request == NTO_DEBUG_PROCESS_INFO || (prp->flags & _NTO_PF_TERMING)) {
		tid = 0;
	} else if(dep && kap->tid == 0) {
		tid = dep->tid + 1;
	} else {
		tid = kap->tid;
	}

	thp = 0;
	if(tid > 0 && !(thp = vector_search(&prp->threads, tid - 1,
			(kap->request == NTO_DEBUG_THREAD_INFO ||
			kap->request == NTO_DEBUG_STOP) ? (unsigned *)&tid : 0))) {
		kererr(act, ESRCH);
		return;
	}

	stopped = 0;
	if(thp && ((thp->flags & _NTO_TF_TO_BE_STOPPED) ||
			(thp->state != STATE_RUNNING && thp->state != STATE_READY))) {
		stopped = 1;
	}

	status = EINVAL;
	switch(kap->request) {
	case NTO_DEBUG_PROCESS_INFO:		// pid:na:debug_process_t
		status =  debug_process(prp, &kap->data->process);
		break;

	case NTO_DEBUG_THREAD_INFO:			// pid:tid:debug_thread_t
		status = debug_thread(prp, thp, &kap->data->thread);
		break;

	case NTO_DEBUG_GET_GREG:			// pid:tid:debug_greg_t
		if(thp) {
			memcpy(&kap->data->greg, &thp->reg, sizeof thp->reg);
			status = EOK;
		}
		break;

	case NTO_DEBUG_SET_GREG:			// pid:tid:debug_greg_t
		if(stopped) {
			lock_kernel();
			cpu_greg_load(thp, (CPU_REGISTERS *)&kap->data->greg);
			status = EOK;
		}
		break;

	case NTO_DEBUG_GET_FPREG:			// pid:tid:debug_fpreg_t
		if(thp) {
			FPU_REGISTERS	*fpudata = FPUDATA_PTR(thp->fpudata);
			int				cpu = FPUDATA_CPU(thp->fpudata);

			status = ENXIO;
			if(fpudata) {
				if(FPUDATA_INUSE(thp->fpudata) && cpu != KERNCPU) {
					// In use on another CPU; send ipi, restart kernel call
					SENDIPI(cpu, IPI_CONTEXT_SAVE);
					KERCALL_RESTART(act);
					return;
				}
				if(actives_fpu[thp->runcpu] == thp) {
					if(KERNCPU == thp->runcpu) {
						cpu_force_fpu_save(thp);
						actives_fpu[KERNCPU] = NULL;
					} else {
						// We should not get here
						crash();
					}
				}
				memcpy(&kap->data->fpreg, fpudata, sizeof *fpudata);
				status = EOK;
			} else if(thp->un.lcl.tls && thp->un.lcl.tls->__fpuemu_data) {
// @@@ NEED TO FIND PROPER SIZE OF EMULATOR DATA
				memcpy(&kap->data->fpreg, thp->un.lcl.tls->__fpuemu_data, sizeof(*fpudata) + 256);
				status = EOK;
			}
		}
		break;
			
	case NTO_DEBUG_SET_FPREG:			// pid:tid:debug_fpreg_t
		if(thp && stopped) {
			FPU_REGISTERS	*fpudata = FPUDATA_PTR(thp->fpudata);
			int				cpu = FPUDATA_CPU(thp->fpudata);

			status = ENXIO;
			if(thp->fpudata) {
				if(FPUDATA_INUSE(thp->fpudata) && cpu != KERNCPU) {
					// In use on another CPU; send ipi, restart kernel call
					SENDIPI(cpu, IPI_CONTEXT_SAVE);
					KERCALL_RESTART(act);
					return;
				}
				if(actives_fpu[thp->runcpu] == thp) {
					if(KERNCPU == thp->runcpu) {
						cpu_force_fpu_save(thp);
						actives_fpu[KERNCPU] = NULL;
					} else {
						// We should not get here
						crash();
					}
				}
				memcpy(fpudata, &kap->data->fpreg, sizeof *fpudata);
				status = EOK;
			} else if(thp->un.lcl.tls && thp->un.lcl.tls->__fpuemu_data) {
// @@@ NEED TO FIND PROPER SIZE OF EMULATOR DATA
				memcpy(thp->un.lcl.tls->__fpuemu_data, &kap->data->fpreg, sizeof(*fpudata) + 256);
				status = EOK;
			}
		}
		break;

	case NTO_DEBUG_STOP:				// pid:na:na
		if(dep) {
			status =  debug_stop(prp);
		}
		break;

	case NTO_DEBUG_RUN:					// pid:tid:debug_run_t
		if(dep && stopped) {
			status = debug_run(prp, &kap->data->run);
		}
		break;

	case NTO_DEBUG_CURTHREAD:			// pid:tid:NULL
		if(dep) {
			lock_kernel();
			SETKSTATUS(act, dep->tid + 1);
			if(thp) {
				dep->tid = thp->tid;
			}
			return;
		}
		break;

	case NTO_DEBUG_FREEZE:				// pid:tid:NULL
		if(thp == NULL){
			status = EINVAL;
			break;
		}
		if(stopped) {
			lock_kernel();
			thp->flags |= _NTO_TF_FROZEN;
		}
		break;

	case NTO_DEBUG_THAW:				// pid:tid:NULL
		if(thp == NULL){
			status = EINVAL;
			break;
		}
		if(stopped) {
			lock_kernel();
			thp->flags &= ~_NTO_TF_FROZEN;
		}
		break;

	case NTO_DEBUG_BREAK:				// pid:na:debug_break_t
		if(dep && stopped) {
			status = debug_break(prp, &kap->data->brk);
		}
		break;

	case NTO_DEBUG_GET_BREAKLIST:		// pid:na:debug_breaklist_t
		status = debug_break_list(prp, &kap->data->brklist);
		break;

	case NTO_DEBUG_SET_FLAG:			// pid:na:uint32_t
		if(dep && !(kap->data->flags & ~_DEBUG_FLAG_MASK)) {
			lock_kernel();
			dep->flags |= kap->data->flags;
		}
		break;

	case NTO_DEBUG_CLEAR_FLAG:			// pid:na:uint32_t
		if(dep && !(kap->data->flags & ~_DEBUG_FLAG_MASK)) {
			lock_kernel();
			dep->flags &= ~kap->data->flags;
		}
		break;

	case NTO_DEBUG_GET_ALTREG:			// pid:tid:debug_altreg_t
		if(thp) {
			status = cpu_debug_get_altregs(thp, &kap->data->altreg);
		}
		break;

	case NTO_DEBUG_SET_ALTREG:			// pid:tid:debug_altreg_t
		if(thp) {
			status = cpu_debug_set_altregs(thp, &kap->data->altreg);
		}
		break;

	case NTO_DEBUG_GET_PERFREG:
		if ( thp ) {
			status = cpu_debug_get_perfregs(thp, &kap->data->perfreg);
		}
		break;

	case NTO_DEBUG_SET_PERFREG:
		if ( thp && !stopped )
			status = EINVAL;
		else {
			if ( (kap->data->flags & ~PERFREGS_ENABLED_FLAG) == cpu_perfreg_id() ) {
				status = cpu_debug_set_perfregs(thp, &kap->data->perfreg);
			}
			else
				status = ENODEV;
		}
		break;
	}

	if(status != EOK) {
		kererr(act, status);
	} else {
		lock_kernel();
		SETKSTATUS(act, 0);
	}
}
Example #8
0
status_t
TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
{
	bool targetIsLocal = true;
		// TODO: Support non-local targets!

	// the first thing we want to do when running
	PostMessage(MSG_LOAD_SETTINGS);

	fTeamID = teamID;

	// create debugger interface
	fDebuggerInterface = new(std::nothrow) DebuggerInterface(fTeamID);
	if (fDebuggerInterface == NULL)
		return B_NO_MEMORY;

	status_t error = fDebuggerInterface->Init();
	if (error != B_OK)
		return error;

	// create file manager
	fFileManager = new(std::nothrow) FileManager;
	if (fFileManager == NULL)
		return B_NO_MEMORY;

	error = fFileManager->Init(targetIsLocal);
	if (error != B_OK)
		return error;

	// create team debug info
	TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
		fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
		fFileManager);
	if (teamDebugInfo == NULL)
		return B_NO_MEMORY;
	BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo);

	error = teamDebugInfo->Init();
	if (error != B_OK)
		return error;

	// check whether the team exists at all
	// TODO: That should be done in the debugger interface!
	team_info teamInfo;
	error = get_team_info(fTeamID, &teamInfo);
	if (error != B_OK)
		return error;

	// create a team object
	fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface,
		fDebuggerInterface->GetArchitecture(), teamDebugInfo,
		teamDebugInfo);
	if (fTeam == NULL)
		return B_NO_MEMORY;

	error = fTeam->Init();
	if (error != B_OK)
		return error;
	fTeam->SetName(teamInfo.args);
		// TODO: Set a better name!

	fTeam->AddListener(this);

	// init thread handler table
	error = fThreadHandlers.Init();
	if (error != B_OK)
		return error;

	// create image handler table
	fImageHandlers = new(std::nothrow) ImageHandlerTable;
	if (fImageHandlers == NULL)
		return B_NO_MEMORY;

	error = fImageHandlers->Init();
	if (error != B_OK)
		return error;

	// create our worker
	fWorker = new(std::nothrow) Worker;
	if (fWorker == NULL)
		return B_NO_MEMORY;

	error = fWorker->Init();
	if (error != B_OK)
		return error;

	// create the breakpoint manager
	fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
		fDebuggerInterface);
	if (fBreakpointManager == NULL)
		return B_NO_MEMORY;

	error = fBreakpointManager->Init();
	if (error != B_OK)
		return error;

	// create the memory block manager
	fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
	if (fMemoryBlockManager == NULL)
		return B_NO_MEMORY;

	error = fMemoryBlockManager->Init();
	if (error != B_OK)
		return error;

	// set team debugging flags
	fDebuggerInterface->SetTeamDebuggingFlags(
		B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES);

	// get the initial state of the team
	AutoLocker< ::Team> teamLocker(fTeam);

	ThreadHandler* mainThreadHandler = NULL;
	{
		BObjectList<ThreadInfo> threadInfos(20, true);
		status_t error = fDebuggerInterface->GetThreadInfos(threadInfos);
		for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) {
			::Thread* thread;
			error = fTeam->AddThread(*info, &thread);
			if (error != B_OK)
				return error;

			ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
				fWorker, fDebuggerInterface,
				fBreakpointManager);
			if (handler == NULL)
				return B_NO_MEMORY;

			fThreadHandlers.Insert(handler);

			if (thread->IsMainThread())
				mainThreadHandler = handler;

			handler->Init();
		}
	}

	Image* appImage = NULL;
	{
		BObjectList<ImageInfo> imageInfos(20, true);
		status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
		for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
			Image* image;
			error = _AddImage(*info, &image);
			if (error != B_OK)
				return error;
			if (image->Type() == B_APP_IMAGE)
				appImage = image;

			ImageDebugInfoRequested(image);
		}
	}

	// create the debug event listener
	char buffer[128];
	snprintf(buffer, sizeof(buffer), "team %ld debug listener", fTeamID);
	fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
		B_NORMAL_PRIORITY, this);
	if (fDebugEventListener < 0)
		return fDebugEventListener;

	resume_thread(fDebugEventListener);

	// run looper
	thread_id looperThread = Run();
	if (looperThread < 0)
		return looperThread;

	// init the UI
	error = fUserInterface->Init(fTeam, this);
	if (error != B_OK) {
		ERROR("Error: Failed to init the UI: %s\n", strerror(error));
		return error;
	}

	// if requested, stop the given thread
	if (threadID >= 0) {
		if (stopInMain) {
			SymbolInfo symbolInfo;
			if (appImage != NULL && mainThreadHandler != NULL
				&& fDebuggerInterface->GetSymbolInfo(
					fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT,
					symbolInfo) == B_OK) {
				mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address());
			}
		} else {
			debug_thread(threadID);
				// TODO: Superfluous, if the thread is already stopped.
		}
	}

	fListener->TeamDebuggerStarted(this);

	return B_OK;
}