Example #1
0
bool
ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
{
	CpuState* cpuState = event->GetCpuState();
	target_addr_t instructionPointer = cpuState->InstructionPointer();

	TRACE_EVENTS("ThreadHandler::HandleBreakpointHit(): ip: %" B_PRIx64 "\n",
		instructionPointer);

	// check whether this is a temporary breakpoint we're waiting for
	if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress
		&& fStepMode != STEP_NONE) {
		if (fStepMode != STEP_UNTIL && _HandleBreakpointHitStep(cpuState))
			return true;
	} else {
		// Might be a user breakpoint, but could as well be a temporary
		// breakpoint of another thread.
		AutoLocker<Team> locker(fThread->GetTeam());
		Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress(
			cpuState->InstructionPointer());
		bool continueThread = false;
		if (breakpoint == NULL) {
			// spurious breakpoint -- might be a temporary breakpoint, that has
			// already been uninstalled
			continueThread = true;
		} else if (!breakpoint->HasEnabledUserBreakpoint()) {
			// breakpoint of another thread or one that has been disabled in
			// the meantime
			continueThread = true;
		}

		if (continueThread) {
			if (fSingleStepping) {
				// We might have hit a just-installed software breakpoint and
				// thus haven't stepped at all. Just try again.
				if (fPreviousInstructionPointer == instructionPointer) {
					fDebuggerInterface->SingleStepThread(ThreadID());
					return true;
				}

				// That shouldn't happen. Try something reasonable anyway.
				if (fStepMode != STEP_NONE) {
					if (_HandleSingleStepStep(cpuState))
						return true;
				}
			}

			return false;
		}
	}

	return _HandleThreadStopped(cpuState, THREAD_STOPPED_BREAKPOINT);
}
Example #2
0
status_t
DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
	::Thread* thread)
{
	AutoLocker< ::Team> locker;
	if (thread->State() != THREAD_STATE_STOPPED)
		return B_OK;

	StackTrace* trace = NULL;
	for (;;) {
		trace = thread->GetStackTrace();
		if (trace != NULL)
			break;

		locker.Unlock();
		status_t result = acquire_sem(fTeamDataSem);
		if (result != B_OK)
			return result;

		locker.Lock();
	}

	_output << "\t\tFrame\t\tIP\t\t\tFunction Name\n";
	_output << "\t\t-----------------------------------------------\n";
	BString data;
	for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) {
		char functionName[512];
		data.SetToFormat("\t\t%#08" B_PRIx64 "\t%#08" B_PRIx64 "\t%s\n",
			frame->FrameAddress(), frame->InstructionPointer(),
			UiUtils::FunctionNameForFrame(frame, functionName,
				sizeof(functionName)));

		_output << data;
	}

	_output << "\n\t\tRegisters:\n";

	CpuState* state = thread->GetCpuState();
	BVariant value;
	const Register* reg = NULL;
	for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) {
		reg = fArchitecture->Registers() + i;
		state->GetRegisterValue(reg, value);

		char buffer[64];
		data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(),
			UiUtils::VariantToString(value, buffer, sizeof(buffer)));
		_output << data;
	}

	return B_OK;
}
Example #3
0
bool
ThreadHandler::_HandleSetAddress(CpuState* state, target_addr_t address)
{
	CpuState* newState = NULL;
	if (state->Clone(newState) != B_OK)
		return false;
	BReference<CpuState> stateReference(newState, true);

	newState->SetInstructionPointer(address);
	if (fDebuggerInterface->SetCpuState(fThread->ID(), newState) != B_OK)
		return false;

	AutoLocker<Team> locker(fThread->GetTeam());
	fThread->SetStackTrace(NULL);
	fThread->SetCpuState(newState);

	return true;
}
status_t
DwarfImageDebugInfo::CreateFrame(Image* image,
	FunctionInstance* functionInstance, CpuState* cpuState,
	bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos,
	StackFrame*& _frame, CpuState*& _previousCpuState)
{
	DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
		functionInstance->GetFunctionDebugInfo());

	FunctionID* functionID = functionInstance->GetFunctionID();
	BReference<FunctionID> functionIDReference;
	if (functionID != NULL)
		functionIDReference.SetTo(functionID, true);

	DIESubprogram* entry = function != NULL
		? function->SubprogramEntry() : NULL;

	TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, "
		"function: %s\n", entry,
		functionID->FunctionName().String());

	int32 registerCount = fArchitecture->CountRegisters();
	const Register* registers = fArchitecture->Registers();

	// get the DWARF <-> architecture register maps
	RegisterMap* toDwarfMap;
	RegisterMap* fromDwarfMap;
	status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
		&fromDwarfMap);
	if (error != B_OK)
		return error;
	BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
	BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);

	// create a clean CPU state for the previous frame
	CpuState* previousCpuState;
	error = fArchitecture->CreateCpuState(previousCpuState);
	if (error != B_OK)
		return error;
	BReference<CpuState> previousCpuStateReference(previousCpuState, true);

	// create the target interfaces
	UnwindTargetInterface* inputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, cpuState, fArchitecture,
			fDebuggerInterface);
	if (inputInterface == NULL)
		return B_NO_MEMORY;
	BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface,
		true);

	UnwindTargetInterface* outputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture,
			fDebuggerInterface);
	if (outputInterface == NULL)
		return B_NO_MEMORY;
	BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface,
		true);

	// do the unwinding
	target_addr_t instructionPointer
		= cpuState->InstructionPointer() - fRelocationDelta;
	target_addr_t framePointer;
	CompilationUnit* unit = function != NULL ? function->GetCompilationUnit()
			: NULL;
	error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry,
		instructionPointer, inputInterface, outputInterface, framePointer);

	if (error != B_OK) {
		TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
		return B_UNSUPPORTED;
	}

	TRACE_CFI_ONLY(
		TRACE_CFI("unwound registers:\n");
		for (int32 i = 0; i < registerCount; i++) {
			const Register* reg = registers + i;
			BVariant value;
			if (previousCpuState->GetRegisterValue(reg, value)) {
				TRACE_CFI("  %3s: %#" B_PRIx64 "\n", reg->Name(),
					value.ToUInt64());
			} else
				TRACE_CFI("  %3s: undefined\n", reg->Name());
		}
	)
status_t
LocalDebuggerInterface::_CreateDebugEvent(int32 messageCode,
	const debug_debugger_message_data& message, bool& _ignore,
	DebugEvent*& _event)
{
	DebugEvent* event = NULL;

	switch (messageCode) {
		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
			event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team,
				message.origin.thread);
			break;
		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
			event = new(std::nothrow) DebuggerCallEvent(message.origin.team,
				message.origin.thread,
				(target_addr_t)message.debugger_call.message);
			break;
		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
		{
			CpuState* state = NULL;
			status_t error = fArchitecture->CreateCpuState(
				&message.breakpoint_hit.cpu_state,
				sizeof(debug_cpu_state), state);
			if (error != B_OK)
				return error;

			event = new(std::nothrow) BreakpointHitEvent(message.origin.team,
				message.origin.thread, state);
			state->ReleaseReference();
			break;
		}
		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
		{
			CpuState* state = NULL;
			status_t error = fArchitecture->CreateCpuState(
				&message.watchpoint_hit.cpu_state,
				sizeof(debug_cpu_state), state);
			if (error != B_OK)
				return error;

			event = new(std::nothrow) WatchpointHitEvent(message.origin.team,
				message.origin.thread, state);
			state->ReleaseReference();
			break;
		}
		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
		{
			CpuState* state = NULL;
			status_t error = fArchitecture->CreateCpuState(
				&message.single_step.cpu_state,
				sizeof(debug_cpu_state), state);
			if (error != B_OK)
				return error;

			event = new(std::nothrow) SingleStepEvent(message.origin.team,
				message.origin.thread, state);
			state->ReleaseReference();
			break;
		}
		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
			event = new(std::nothrow) ExceptionOccurredEvent(
				message.origin.team, message.origin.thread,
				message.exception_occurred.exception);
			break;
		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
			if (message.origin.team != fTeamID) {
				_ignore = true;
				return B_OK;
			}
			event = new(std::nothrow) TeamDeletedEvent(message.origin.team,
				message.origin.thread);
			break;
		case B_DEBUGGER_MESSAGE_TEAM_EXEC:
			if (message.origin.team != fTeamID) {
				_ignore = true;
				return B_OK;
			}
			event = new(std::nothrow) TeamExecEvent(message.origin.team,
				message.origin.thread);
			break;
		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
			event = new(std::nothrow) ThreadCreatedEvent(message.origin.team,
				message.origin.thread, message.thread_created.new_thread);
			break;
		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
			event = new(std::nothrow) ThreadDeletedEvent(message.origin.team,
				message.origin.thread);
			break;
		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
		{
			const image_info& info = message.image_created.info;
			event = new(std::nothrow) ImageCreatedEvent(message.origin.team,
				message.origin.thread,
				ImageInfo(fTeamID, info.id, info.name, info.type,
					(addr_t)info.text, info.text_size, (addr_t)info.data,
					info.data_size));
			break;
		}
		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
		{
			const image_info& info = message.image_deleted.info;
			event = new(std::nothrow) ImageDeletedEvent(message.origin.team,
				message.origin.thread,
				ImageInfo(fTeamID, info.id, info.name, info.type,
					(addr_t)info.text, info.text_size, (addr_t)info.data,
					info.data_size));
			break;
		}
		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
		{
			event = new(std::nothrow) PostSyscallEvent(message.origin.team,
				message.origin.thread,
				SyscallInfo(message.post_syscall.start_time,
					message.post_syscall.end_time,
					message.post_syscall.return_value,
					message.post_syscall.syscall, message.post_syscall.args));
			break;
		}
		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
		{
			event = new(std::nothrow) SignalReceivedEvent(message.origin.team,
				message.origin.thread,
				SignalInfo(message.signal_received.signal,
					message.signal_received.handler,
					message.signal_received.deadly));
			break;
		}
		default:
			printf("DebuggerInterface for team %" B_PRId32 ": unknown message "
				"from kernel: %" B_PRId32 "\n", fTeamID, messageCode);
			// fall through...
		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
		case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
		case B_DEBUGGER_MESSAGE_HANDED_OVER:
			_ignore = true;
			return B_OK;
	}

	if (event == NULL)
		return B_NO_MEMORY;

	if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
		event->SetThreadStopped(true);

	_ignore = false;
	_event = event;

	return B_OK;
}
Example #6
0
status_t
DwarfImageDebugInfo::CreateFrame(Image* image,
	FunctionInstance* functionInstance, CpuState* cpuState,
	StackFrame*& _previousFrame, CpuState*& _previousCpuState)
{
	DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
		functionInstance->GetFunctionDebugInfo());
	if (function == NULL)
		return B_BAD_VALUE;

	TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p\n",
		function->SubprogramEntry());

	int32 registerCount = fArchitecture->CountRegisters();
	const Register* registers = fArchitecture->Registers();

	// get the DWARF <-> architecture register maps
	RegisterMap* toDwarfMap;
	RegisterMap* fromDwarfMap;
	status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
		&fromDwarfMap);
	if (error != B_OK)
		return error;
	Reference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
	Reference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);

	// create a clean CPU state for the previous frame
	CpuState* previousCpuState;
	error = fArchitecture->CreateCpuState(previousCpuState);
	if (error != B_OK)
		return error;
	Reference<CpuState> previousCpuStateReference(previousCpuState, true);

	// create the target interfaces
	UnwindTargetInterface* inputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, cpuState, fArchitecture, fTeamMemory);
	if (inputInterface == NULL)
		return B_NO_MEMORY;
	Reference<UnwindTargetInterface> inputInterfaceReference(inputInterface,
		true);

	UnwindTargetInterface* outputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture,
			fTeamMemory);
	if (outputInterface == NULL)
		return B_NO_MEMORY;
	Reference<UnwindTargetInterface> outputInterfaceReference(outputInterface,
		true);

	// do the unwinding
	target_addr_t instructionPointer
		= cpuState->InstructionPointer() - fRelocationDelta;
	target_addr_t framePointer;
	CompilationUnit* unit = function->GetCompilationUnit();
	error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(),
		instructionPointer, inputInterface, outputInterface, framePointer);
	if (error != B_OK) {
		TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
		return B_UNSUPPORTED;
	}

	TRACE_CFI_ONLY(
		TRACE_CFI("unwound registers:\n");
		for (int32 i = 0; i < registerCount; i++) {
			const Register* reg = registers + i;
			BVariant value;
			if (previousCpuState->GetRegisterValue(reg, value))
				TRACE_CFI("  %3s: %#lx\n", reg->Name(), value.ToUInt32());
			else
				TRACE_CFI("  %3s: undefined\n", reg->Name());
		}
	)
status_t
DebugReportGenerator::_DumpDebuggedThreadInfo(BFile& _output,
	::Thread* thread)
{
	AutoLocker< ::Team> locker;
	if (thread->State() != THREAD_STATE_STOPPED)
		return B_OK;

	status_t error;
	StackTrace* trace = NULL;
	for (;;) {
		trace = thread->GetStackTrace();
		if (trace != NULL)
			break;

		locker.Unlock();
		fTraceWaitingThread = thread;
		do {
			error = acquire_sem(fTeamDataSem);
		} while (error == B_INTERRUPTED);

		if (error != B_OK)
			break;

		locker.Lock();
	}

	BString data("\t\tFrame\t\tIP\t\t\tFunction Name\n");
	WRITE_AND_CHECK(_output, data);
	data = "\t\t-----------------------------------------------\n";
	WRITE_AND_CHECK(_output, data);
	for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) {
		char functionName[512];
		BString sourcePath;

		target_addr_t ip = frame->InstructionPointer();
		FunctionInstance* functionInstance;
		Statement* statement;
		if (fTeam->GetStatementAtAddress(ip,
				functionInstance, statement) == B_OK) {
			BReference<Statement> statementReference(statement, true);

			int32 line = statement->StartSourceLocation().Line();
			LocatableFile* sourceFile = functionInstance->GetFunction()
				->SourceFile();
			if (sourceFile != NULL) {
				sourceFile->GetPath(sourcePath);
				sourcePath.SetToFormat("(%s:%" B_PRId32 ")",
					sourcePath.String(), line);
			}
		}


		data.SetToFormat("\t\t%#08" B_PRIx64 "\t%#08" B_PRIx64 "\t%s %s\n",
			frame->FrameAddress(), ip, UiUtils::FunctionNameForFrame(
				frame, functionName, sizeof(functionName)),
				sourcePath.String());

		WRITE_AND_CHECK(_output, data);

		// only dump the topmost frame
		if (i == 0) {
			locker.Unlock();
			error = _DumpFunctionDisassembly(_output, frame->InstructionPointer());
			if (error != B_OK)
				return error;
			error = _DumpStackFrameMemory(_output, thread->GetCpuState(),
				frame->FrameAddress(), thread->GetTeam()->GetArchitecture()
					->StackGrowthDirection());
			if (error != B_OK)
				return error;
			locker.Lock();
		}

		if (frame->CountParameters() == 0 && frame->CountLocalVariables() == 0)
			continue;

		data = "\t\t\tVariables:\n";
		WRITE_AND_CHECK(_output, data);
		error = fNodeManager->SetStackFrame(thread, frame);
		if (error != B_OK)
			continue;

		ValueNodeContainer* container = fNodeManager->GetContainer();
		AutoLocker<ValueNodeContainer> containerLocker(container);
		for (int32 i = 0; i < container->CountChildren(); i++) {
			data.Truncate(0L);
			ValueNodeChild* child = container->ChildAt(i);
			containerLocker.Unlock();
			_ResolveValueIfNeeded(child->Node(), frame, 1);
			containerLocker.Lock();
			UiUtils::PrintValueNodeGraph(data, child, 3, 1);
			WRITE_AND_CHECK(_output, data);
		}
		data = "\n";
		WRITE_AND_CHECK(_output, data);
	}

	data = "\n\t\tRegisters:\n";
	WRITE_AND_CHECK(_output, data);

	CpuState* state = thread->GetCpuState();
	BVariant value;
	const Register* reg = NULL;
	for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) {
		reg = fArchitecture->Registers() + i;
		state->GetRegisterValue(reg, value);

		if (reg->Format() == REGISTER_FORMAT_SIMD) {
			data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(),
				UiUtils::FormatSIMDValue(value, reg->BitSize(),
					SIMD_RENDER_FORMAT_INT16, data).String());
		} else {
			char buffer[64];
			data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(),
				UiUtils::VariantToString(value, buffer, sizeof(buffer)));
		}

		WRITE_AND_CHECK(_output, data);
	}

	return B_OK;
}