bool ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) { TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep(): ip: %llx\n", cpuState->InstructionPointer()); switch (fStepMode) { case STEP_INTO: { // We continue stepping as long as we're in the statement. if (fStepStatement->ContainsAddress(cpuState->InstructionPointer())) { _SingleStepThread(cpuState->InstructionPointer()); return true; } StackTrace* stackTrace = fThread->GetStackTrace(); BReference<StackTrace> stackTraceReference(stackTrace); if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( fThread->GetTeam(), this, cpuState, stackTrace) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } if (stackTrace != NULL) { StackFrame* frame = stackTrace->FrameAt(0); Image* image = frame->GetImage(); ImageDebugInfo* info = NULL; if (GetImageDebugInfo(image, info) != B_OK) return false; BReference<ImageDebugInfo>(info, true); if (info->GetAddressSectionType( cpuState->InstructionPointer()) == ADDRESS_SECTION_TYPE_PLT) { _SingleStepThread(cpuState->InstructionPointer()); return true; } } return false; } case STEP_OVER: { // If we have stepped out of the statement, we're done. if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer())) return false; return _DoStepOver(cpuState); } case STEP_OUT: // We never single-step in this case. default: return false; } }
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; }
void CliStackTraceCommand::Execute(int argc, const char* const* argv, CliContext& context) { // get the current thread Team* team = context.GetTeam(); AutoLocker<Team> teamLocker(team); Thread* thread = context.CurrentThread(); if (thread == NULL) { printf("no current thread\n"); return; } if (thread->State() != THREAD_STATE_STOPPED) { printf("Current thread is not stopped. Can't get stack trace.\n"); return; } // get its stack trace StackTrace* stackTrace = thread->GetStackTrace(); while (stackTrace == NULL) { context.WaitForEvents(CliContext::EVENT_THREAD_STACK_TRACE_CHANGED); if (context.IsTerminating()) return; stackTrace = thread->GetStackTrace(); } BReference<StackTrace> stackTraceReference(stackTrace); // hold a reference until we're done teamLocker.Unlock(); // print the stack trace int32 frameCount = stackTrace->CountFrames(); for (int32 i = 0; i < frameCount; i++) { StackFrame* frame = stackTrace->FrameAt(i); printf("%3" B_PRId32 " %#" B_PRIx64 " %#" B_PRIx64, i, (uint64)frame->FrameAddress(), (uint64)frame->InstructionPointer()); char functionName[512]; UiUtils::FunctionNameForFrame(frame, functionName, sizeof(functionName)); printf(" %s\n", functionName); } }
bool ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) { // in any case uninstall the temporary breakpoint _UninstallTemporaryBreakpoint(); switch (fStepMode) { case STEP_OVER: { StackTrace* stackTrace = fThread->GetStackTrace(); BReference<StackTrace> stackTraceReference(stackTrace); if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1, false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } if (stackTrace != NULL) { StackFrame* frame = stackTrace->FrameAt(0); // If we're not in the same frame we started in, // keep executing. if (frame != NULL && fPreviousFrameAddress != frame->FrameAddress()) { status_t error = _InstallTemporaryBreakpoint( cpuState->InstructionPointer()); if (error != B_OK) _StepFallback(); else _RunThread(cpuState->InstructionPointer()); return true; } } if (fPreviousFrameAddress != 0 && fSteppedOverFunctionAddress != cpuState->InstructionPointer()) { TRACE_CONTROL("STEP_OVER: called function address %#" B_PRIx64 ", previous frame address: %#" B_PRIx64 ", frame address: %#" B_PRIx64 ", adding return info\n", fSteppedOverFunctionAddress, fPreviousFrameAddress, stackTrace->FrameAt(0)->FrameAddress()); ReturnValueInfo* returnInfo = new(std::nothrow) ReturnValueInfo( fSteppedOverFunctionAddress, cpuState); if (returnInfo == NULL) return false; BReference<ReturnValueInfo> returnInfoReference(returnInfo, true); if (fThread->AddReturnValueInfo(returnInfo) != B_OK) return false; returnInfoReference.Detach(); fSteppedOverFunctionAddress = 0; } // If we're still in the statement, we continue single-stepping, // otherwise we're done. if (fStepStatement->ContainsAddress( cpuState->InstructionPointer())) { if (!_DoStepOver(cpuState)) _StepFallback(); return true; } fPreviousFrameAddress = 0; return false; } case STEP_INTO: // Should never happen -- we don't set a breakpoint in this case. return false; case STEP_OUT: { // That's the return address, so we're done in theory, // unless we're a recursive function. Check if we've actually // exited the previous stack frame or not if (!_HasExitedFrame(cpuState->StackFramePointer())) { status_t error = _InstallTemporaryBreakpoint( cpuState->InstructionPointer()); if (error != B_OK) _StepFallback(); else _RunThread(cpuState->InstructionPointer()); return true; } if (fPreviousFrameAddress == 0) return false; TRACE_CONTROL("ThreadHandler::_HandleBreakpointHitStep() - " "frame pointer 0x%#" B_PRIx64 ", previous: 0x%#" B_PRIx64 " - step out adding return value\n", cpuState ->StackFramePointer(), fPreviousFrameAddress); ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo( fPreviousInstructionPointer, cpuState); if (info == NULL) return false; BReference<ReturnValueInfo> infoReference(info, true); if (fThread->AddReturnValueInfo(info) != B_OK) return false; infoReference.Detach(); fPreviousFrameAddress = 0; } default: return false; } }
void ThreadHandler::HandleThreadAction(uint32 action, target_addr_t address) { AutoLocker<Team> locker(fThread->GetTeam()); if (fThread->State() == THREAD_STATE_UNKNOWN) return; // When stop is requested, thread must be running, otherwise stopped. if (action == MSG_THREAD_STOP ? fThread->State() != THREAD_STATE_RUNNING : fThread->State() != THREAD_STATE_STOPPED) { return; } // When stepping we need a stack trace. Save it before unsetting the state. CpuState* cpuState = fThread->GetCpuState(); StackTrace* stackTrace = fThread->GetStackTrace(); BReference<CpuState> cpuStateReference(cpuState); BReference<StackTrace> stackTraceReference(stackTrace); if (action == MSG_THREAD_SET_ADDRESS) { _HandleSetAddress(cpuState, address); return; } // When continuing the thread update thread state before actually issuing // the command, since we need to unlock. if (action != MSG_THREAD_STOP) { _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN, BString()); } locker.Unlock(); switch (action) { case MSG_THREAD_RUN: fStepMode = address != 0 ? STEP_UNTIL : STEP_NONE; if (address != 0) _InstallTemporaryBreakpoint(address); _RunThread(0); return; case MSG_THREAD_STOP: fStepMode = STEP_NONE; if (fDebuggerInterface->StopThread(ThreadID()) == B_OK) fThread->SetStopRequestPending(); return; case MSG_THREAD_STEP_OVER: case MSG_THREAD_STEP_INTO: case MSG_THREAD_STEP_OUT: break; } TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n"); // We want to step. We need a stack trace for that purpose. If we don't // have one yet, get it. Start with the CPU state. if (stackTrace == NULL && cpuState == NULL) { if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK) cpuStateReference.SetTo(cpuState, true); } if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1, false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } if (stackTrace == NULL || stackTrace->CountFrames() == 0) { _StepFallback(); return; } StackFrame* frame = stackTrace->FrameAt(0); TRACE_CONTROL(" ip: %#" B_PRIx64 "\n", frame->InstructionPointer()); target_addr_t frameIP = frame->GetCpuState()->InstructionPointer(); // When the thread is in a syscall, do the same for all step kinds: Stop it // when it returns by means of a breakpoint. if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) { // set a breakpoint at the CPU state's instruction pointer (points to // the return address, unlike the stack frame's instruction pointer) // TODO: This is doesn't work correctly anymore. When stepping over a "syscall" // instruction the thread is stopped twice. The after the first step the PC is // incorrectly shown at the "syscall" instruction. Then we step again and are // stopped at the temporary breakpoint after the "syscall" instruction. There // are two problems. The first one is that we don't (cannot?) discriminate // between the thread being in a syscall (like in a blocking syscall) and the // thread having been stopped (or singled-stepped) at the end of the syscall. // The second issue is that the temporary breakpoint is probably not necessary // anymore, since single-stepping over "syscall" instructions should just work // as expected. status_t error = _InstallTemporaryBreakpoint(frameIP); if (error != B_OK) { _StepFallback(); return; } fStepMode = STEP_OUT; _RunThread(frameIP); return; } // For "step out" just set a temporary breakpoint on the return address. if (action == MSG_THREAD_STEP_OUT) { status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress()); if (error != B_OK) { _StepFallback(); return; } fPreviousInstructionPointer = frameIP; fPreviousFrameAddress = frame->FrameAddress(); fStepMode = STEP_OUT; _RunThread(frameIP); return; } // For "step in" and "step over" we also need the source code statement at // the current instruction pointer. fStepStatement = _GetStatementAtInstructionPointer(frame); if (fStepStatement == NULL) { _StepFallback(); return; } TRACE_CONTROL(" statement: %#" B_PRIx64 " - %#" B_PRIx64 "\n", fStepStatement->CoveringAddressRange().Start(), fStepStatement->CoveringAddressRange().End()); if (action == MSG_THREAD_STEP_INTO) { // step into fStepMode = STEP_INTO; _SingleStepThread(frameIP); } else { fPreviousFrameAddress = frame->FrameAddress(); // step over fStepMode = STEP_OVER; if (!_DoStepOver(frame->GetCpuState())) _StepFallback(); } }
status_t Architecture::CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, StackTrace*& _stackTrace, int32 maxStackDepth, bool useExistingTrace) { BReference<CpuState> cpuStateReference(cpuState); StackTrace* stackTrace = NULL; ObjectDeleter<StackTrace> stackTraceDeleter; StackFrame* frame = NULL; if (useExistingTrace) stackTrace = _stackTrace; else { // create the object stackTrace = new(std::nothrow) StackTrace; if (stackTrace == NULL) return B_NO_MEMORY; stackTraceDeleter.SetTo(stackTrace); } // if we're passed an already existing partial stack trace, // attempt to continue building it from where it left off. if (stackTrace->CountFrames() > 0) { frame = stackTrace->FrameAt(stackTrace->CountFrames() - 1); cpuState = frame->GetCpuState(); } while (cpuState != NULL) { // get the instruction pointer target_addr_t instructionPointer = cpuState->InstructionPointer(); if (instructionPointer == 0) break; // get the image for the instruction pointer AutoLocker<Team> teamLocker(team); Image* image = team->ImageByAddress(instructionPointer); BReference<Image> imageReference(image); teamLocker.Unlock(); // get the image debug info ImageDebugInfo* imageDebugInfo = NULL; if (image != NULL) imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo); BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true); // get the function teamLocker.Lock(); FunctionInstance* function = NULL; FunctionDebugInfo* functionDebugInfo = NULL; if (imageDebugInfo != NULL) { function = imageDebugInfo->FunctionAtAddress(instructionPointer); if (function != NULL) functionDebugInfo = function->GetFunctionDebugInfo(); } BReference<FunctionInstance> functionReference(function); teamLocker.Unlock(); // If the CPU state's instruction pointer is actually the return address // of the next frame, we let the architecture fix that. if (frame != NULL && frame->ReturnAddress() == cpuState->InstructionPointer()) { UpdateStackFrameCpuState(frame, image, functionDebugInfo, cpuState); } // create the frame using the debug info StackFrame* previousFrame = NULL; CpuState* previousCpuState = NULL; if (function != NULL) { status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->CreateFrame(image, function, cpuState, previousFrame, previousCpuState); if (error != B_OK && error != B_UNSUPPORTED) break; } // If we have no frame yet, let the architecture create it. if (previousFrame == NULL) { status_t error = CreateStackFrame(image, functionDebugInfo, cpuState, frame == NULL, previousFrame, previousCpuState); if (error != B_OK) break; } cpuStateReference.SetTo(previousCpuState, true); previousFrame->SetImage(image); previousFrame->SetFunction(function); if (!stackTrace->AddFrame(previousFrame)) { delete previousFrame; return B_NO_MEMORY; } frame = previousFrame; cpuState = previousCpuState; if (--maxStackDepth == 0) break; } stackTraceDeleter.Detach(); _stackTrace = stackTrace; return B_OK; }
bool ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) { // in any case uninstall the temporary breakpoint _UninstallTemporaryBreakpoint(); switch (fStepMode) { case STEP_OVER: { StackTrace* stackTrace = fThread->GetStackTrace(); BReference<StackTrace> stackTraceReference(stackTrace); if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( fThread->GetTeam(), this, cpuState, stackTrace, 0, 1, false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } if (stackTrace != NULL) { StackFrame* frame = stackTrace->FrameAt(0); // If we're not in the same frame we started in, // keep executing. if (frame != NULL && fPreviousFrameAddress != frame->FrameAddress()) { status_t error = _InstallTemporaryBreakpoint( cpuState->InstructionPointer()); if (error != B_OK) _StepFallback(); else _RunThread(cpuState->InstructionPointer()); return true; } } // If we're still in the statement, we continue single-stepping, // otherwise we're done. if (fStepStatement->ContainsAddress( cpuState->InstructionPointer())) { if (!_DoStepOver(cpuState)) _StepFallback(); return true; } fPreviousFrameAddress = 0; return false; } case STEP_INTO: // Should never happen -- we don't set a breakpoint in this case. return false; case STEP_OUT: { // That's the return address, so we're done in theory, // unless we're a recursive function. Check if we've actually // exited the previous stack frame or not. fThread->SetExecutedSubroutine(cpuState->InstructionPointer()); target_addr_t framePointer = cpuState->StackFramePointer(); bool hasExitedFrame = fDebuggerInterface->GetArchitecture() ->StackGrowthDirection() == STACK_GROWTH_DIRECTION_POSITIVE ? framePointer < fPreviousFrameAddress : framePointer > fPreviousFrameAddress; if (!hasExitedFrame) { status_t error = _InstallTemporaryBreakpoint( cpuState->InstructionPointer()); if (error != B_OK) _StepFallback(); else _RunThread(cpuState->InstructionPointer()); return true; } fPreviousFrameAddress = 0; } default: return false; } }
void ThreadHandler::HandleThreadAction(uint32 action) { AutoLocker<Team> locker(fThread->GetTeam()); if (fThread->State() == THREAD_STATE_UNKNOWN) return; // When stop is requested, thread must be running, otherwise stopped. if (action == MSG_THREAD_STOP ? fThread->State() != THREAD_STATE_RUNNING : fThread->State() != THREAD_STATE_STOPPED) { return; } // When stepping we need a stack trace. Save it before unsetting the state. CpuState* cpuState = fThread->GetCpuState(); StackTrace* stackTrace = fThread->GetStackTrace(); Reference<CpuState> cpuStateReference(cpuState); Reference<StackTrace> stackTraceReference(stackTrace); // When continuing the thread update thread state before actually issuing // the command, since we need to unlock. if (action != MSG_THREAD_STOP) { _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN, BString()); } locker.Unlock(); switch (action) { case MSG_THREAD_RUN: fStepMode = STEP_NONE; _RunThread(0); return; case MSG_THREAD_STOP: fStepMode = STEP_NONE; fDebuggerInterface->StopThread(ThreadID()); return; case MSG_THREAD_STEP_OVER: case MSG_THREAD_STEP_INTO: case MSG_THREAD_STEP_OUT: break; } TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n"); // We want to step. We need a stack trace for that purpose. If we don't // have one yet, get it. Start with the CPU state. if (stackTrace == NULL && cpuState == NULL) { if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK) cpuStateReference.SetTo(cpuState, true); } if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( fThread->GetTeam(), this, cpuState, stackTrace) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } if (stackTrace == NULL || stackTrace->CountFrames() == 0) { _StepFallback(); return; } StackFrame* frame = stackTrace->FrameAt(0); TRACE_CONTROL(" ip: %#llx\n", frame->InstructionPointer()); // When the thread is in a syscall, do the same for all step kinds: Stop it // when it return by means of a breakpoint. if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) { // set a breakpoint at the CPU state's instruction pointer (points to // the return address, unlike the stack frame's instruction pointer) status_t error = _InstallTemporaryBreakpoint( frame->GetCpuState()->InstructionPointer()); if (error != B_OK) { _StepFallback(); return; } fStepMode = STEP_OUT; _RunThread(frame->GetCpuState()->InstructionPointer()); return; } // For "step out" just set a temporary breakpoint on the return address. if (action == MSG_THREAD_STEP_OUT) { // TODO: That's OK in principle, but needs additional work with recursive // functions. We need to store some information that allows us to determine // whether we've actually stepped out of the current frame when we have hit // the breakpoint. status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress()); if (error != B_OK) { _StepFallback(); return; } fStepMode = STEP_OUT; _RunThread(frame->GetCpuState()->InstructionPointer()); return; } // For "step in" and "step over" we also need the source code statement at // the current instruction pointer. fStepStatement = _GetStatementAtInstructionPointer(frame); if (fStepStatement == NULL) { _StepFallback(); return; } TRACE_CONTROL(" statement: %#llx - %#llx\n", fStepStatement->CoveringAddressRange().Start(), fStepStatement->CoveringAddressRange().End()); if (action == MSG_THREAD_STEP_INTO) { // step into fStepMode = STEP_INTO; _SingleStepThread(frame->GetCpuState()->InstructionPointer()); } else { // step over fStepMode = STEP_OVER; if (!_DoStepOver(frame->GetCpuState())) _StepFallback(); } }
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; }