diff --git a/src/apps/debugger/controllers/DebugReportGenerator.cpp b/src/apps/debugger/controllers/DebugReportGenerator.cpp index e89bf7fb4d..dd09bde244 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.cpp +++ b/src/apps/debugger/controllers/DebugReportGenerator.cpp @@ -41,6 +41,14 @@ #include "ValueNodeManager.h" +#define WRITE_AND_CHECK(output, data) \ + { \ + ssize_t error = output.Write(data.String(), data.Length()); \ + if (error < 0) \ + return error; \ + } + + DebugReportGenerator::DebugReportGenerator(::Team* team, UserInterfaceListener* listener, DebuggerInterface* interface) : @@ -121,31 +129,26 @@ DebugReportGenerator::_GenerateReport(const entry_ref& outputPath) if (result != B_OK) return result; - BString output; - result = _GenerateReportHeader(output); + result = _GenerateReportHeader(file); if (result != B_OK) return result; - result = _DumpRunningThreads(output); + result = _DumpRunningThreads(file); if (result != B_OK) return result; - result = _DumpLoadedImages(output); + result = _DumpLoadedImages(file); if (result != B_OK) return result; - result = _DumpAreas(output); + result = _DumpAreas(file); if (result != B_OK) return result; - result = _DumpSemaphores(output); + result = _DumpSemaphores(file); if (result != B_OK) return result; - result = file.Write(output.String(), output.Length()); - if (result < 0) - return result; - BPath path(&outputPath); fTeam->NotifyDebugReportChanged(path.Path()); @@ -223,14 +226,14 @@ DebugReportGenerator::FunctionSourceCodeChanged(Function* function) } status_t -DebugReportGenerator::_GenerateReportHeader(BString& _output) +DebugReportGenerator::_GenerateReportHeader(BFile& _output) { AutoLocker< ::Team> locker(fTeam); BString data; data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n", fTeam->Name(), fTeam->ID()); - _output << data; + WRITE_AND_CHECK(_output, data); SystemInfo sysInfo; @@ -268,7 +271,8 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output) data.SetToFormat("CPU(s): %" B_PRId32 "x %s %s\n", info.cpu_count, get_cpu_vendor_string(cpuVendor), get_cpu_model_string(platform, cpuVendor, cpuModel)); - _output << data; + WRITE_AND_CHECK(_output, data); + char maxSize[32]; char usedSize[32]; @@ -277,12 +281,12 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output) maxSize, sizeof(maxSize)), BPrivate::string_for_size((int64)info.used_pages * B_PAGE_SIZE, usedSize, sizeof(usedSize))); - _output << data; + WRITE_AND_CHECK(_output, data); const utsname& name = sysInfo.GetSystemName(); data.SetToFormat("Haiku revision: %s (%s)\n", name.version, name.machine); - _output << data; + WRITE_AND_CHECK(_output, data); } delete[] topology; @@ -291,13 +295,13 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output) status_t -DebugReportGenerator::_DumpLoadedImages(BString& _output) +DebugReportGenerator::_DumpLoadedImages(BFile& _output) { AutoLocker< ::Team> locker(fTeam); - _output << "\nLoaded Images:\n"; + BString data("\nLoaded Images:\n"); + WRITE_AND_CHECK(_output, data); BObjectList images; - BString data; for (ImageList::ConstIterator it = fTeam->Images().GetIterator(); Image* image = it.Next();) { images.AddItem(image); @@ -308,9 +312,11 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output) Image* image = NULL; data.SetToFormat("\tID\t\tText Base\tText End\tData Base\tData" " End\tType\tName\n\t"); - _output << data; - _output.Append('-', 80); - _output.Append("\n"); + WRITE_AND_CHECK(_output, data); + data.Truncate(0L); + data.Append('-', 80); + data.Append("\n"); + WRITE_AND_CHECK(_output, data); for (int32 i = 0; (image = images.ItemAt(i)) != NULL; i++) { const ImageInfo& info = image->Info(); char buffer[32]; @@ -325,7 +331,7 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output) UiUtils::ImageTypeToString(info.Type(), buffer, sizeof(buffer)), info.Name().String()); - _output << data; + WRITE_AND_CHECK(_output, data); } catch (...) { return B_NO_MEMORY; } @@ -336,7 +342,7 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output) status_t -DebugReportGenerator::_DumpAreas(BString& _output) +DebugReportGenerator::_DumpAreas(BFile& _output) { BObjectList areas(20, true); status_t result = fDebuggerInterface->GetAreaInfos(areas); @@ -345,12 +351,14 @@ DebugReportGenerator::_DumpAreas(BString& _output) areas.SortItems(&_CompareAreas); - _output << "\nAreas:\n"; - BString data; + BString data("\nAreas:\n"); + WRITE_AND_CHECK(_output, data); data.SetToFormat("\tID\t\tBase\t\tEnd\t\t\tSize (KiB)\tProtection\tLocking\t\t\tName\n\t"); - _output << data; - _output.Append('-', 80); - _output.Append("\n"); + WRITE_AND_CHECK(_output, data); + data.Truncate(0L); + data.Append('-', 80); + data.Append("\n"); + WRITE_AND_CHECK(_output, data); AreaInfo* info; BString protectionBuffer; char lockingBuffer[32]; @@ -365,35 +373,38 @@ DebugReportGenerator::_DumpAreas(BString& _output) UiUtils::AreaLockingFlagsToString(info->Lock(), lockingBuffer, sizeof(lockingBuffer)), info->Name().String()); - _output << data; + WRITE_AND_CHECK(_output, data); } catch (...) { return B_NO_MEMORY; } } - _output << "\nProtection Flags: r - read, w - write, x - execute, " + data = "\nProtection Flags: r - read, w - write, x - execute, " "s - stack, o - overcommit, c - cloneable, S - shared, k - kernel\n"; + WRITE_AND_CHECK(_output, data); return B_OK; } status_t -DebugReportGenerator::_DumpSemaphores(BString& _output) +DebugReportGenerator::_DumpSemaphores(BFile& _output) { BObjectList semaphores(20, true); - status_t result = fDebuggerInterface->GetSemaphoreInfos(semaphores); - if (result != B_OK) - return result; + status_t error = fDebuggerInterface->GetSemaphoreInfos(semaphores); + if (error != B_OK) + return error; semaphores.SortItems(&_CompareSemaphores); - _output << "\nSemaphores:\n"; - BString data; + BString data = "\nSemaphores:\n"; + WRITE_AND_CHECK(_output, data); data.SetToFormat("\tID\t\tCount\tLast Holder\tName\n\t"); - _output << data; - _output.Append('-', 60); - _output.Append("\n"); + WRITE_AND_CHECK(_output, data); + data.Truncate(0L); + data.Append('-', 60); + data.Append("\n"); + WRITE_AND_CHECK(_output, data); SemaphoreInfo* info; for (int32 i = 0; (info = semaphores.ItemAt(i)) != NULL; i++) { try { @@ -401,7 +412,7 @@ DebugReportGenerator::_DumpSemaphores(BString& _output) "\t%s\n", info->SemID(), info->Count(), info->LatestHolder(), info->Name().String()); - _output << data; + WRITE_AND_CHECK(_output, data); } catch (...) { return B_NO_MEMORY; } @@ -412,13 +423,12 @@ DebugReportGenerator::_DumpSemaphores(BString& _output) status_t -DebugReportGenerator::_DumpRunningThreads(BString& _output) +DebugReportGenerator::_DumpRunningThreads(BFile& _output) { AutoLocker< ::Team> locker(fTeam); - _output << "\nActive Threads:\n"; - BString data; - status_t result = B_OK; + BString data("\nActive Threads:\n"); + WRITE_AND_CHECK(_output, data); BObjectList< ::Thread> threads; ::Thread* thread; for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator(); @@ -429,10 +439,10 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output) threads.SortItems(&_CompareThreads); for (int32 i = 0; (thread = threads.ItemAt(i)) != NULL; i++) { try { - data.SetToFormat("\tthread %" B_PRId32 ": %s %s", thread->ID(), + data.SetToFormat("\tthread %" B_PRId32 ": %s %s\n", thread->ID(), thread->Name(), thread->IsMainThread() ? "(main)" : ""); - _output << data << "\n"; + WRITE_AND_CHECK(_output, data); if (thread->State() == THREAD_STATE_STOPPED) { data.SetToFormat("\t\tstate: %s", @@ -441,18 +451,19 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output) const BString& stoppedInfo = thread->StoppedReasonInfo(); if (stoppedInfo.Length() != 0) data << " (" << stoppedInfo << ")"; - _output << data << "\n\n"; + data << "\n\n"; + WRITE_AND_CHECK(_output, data); // we need to release our lock on the team here // since we might need to block and wait // on the stack trace. BReference< ::Thread> threadRef(thread); locker.Unlock(); - result = _DumpDebuggedThreadInfo(_output, thread); + status_t error = _DumpDebuggedThreadInfo(_output, thread); + if (error != B_OK) + return error; locker.Lock(); } - if (result != B_OK) - return result; } catch (...) { return B_NO_MEMORY; } @@ -463,13 +474,14 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output) status_t -DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, +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(); @@ -478,16 +490,19 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, locker.Unlock(); fTraceWaitingThread = thread; - status_t result = acquire_sem(fTeamDataSem); - if (result != B_OK) - return result; + error = acquire_sem(fTeamDataSem); + if (error == B_INTERRUPTED) + continue; + else if (error != B_OK) + return error; locker.Lock(); } - _output << "\t\tFrame\t\tIP\t\t\tFunction Name\n"; - _output << "\t\t-----------------------------------------------\n"; - BString data; + 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; @@ -515,39 +530,48 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, frame, functionName, sizeof(functionName)), sourcePath.String()); - _output << data; + WRITE_AND_CHECK(_output, data); // only dump the topmost frame if (i == 0) { locker.Unlock(); - _DumpFunctionDisassembly(_output, frame->InstructionPointer()); - _DumpStackFrameMemory(_output, thread->GetCpuState(), + 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; - _output << "\t\t\tVariables:\n"; - status_t result = fNodeManager->SetStackFrame(thread, frame); - if (result != B_OK) + 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 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(_output, child, 3, 1); + UiUtils::PrintValueNodeGraph(data, child, 3, 1); + WRITE_AND_CHECK(_output, data); } - _output << "\n"; + data = "\n"; + WRITE_AND_CHECK(_output, data); } - _output << "\n\t\tRegisters:\n"; + data = "\n\t\tRegisters:\n"; + WRITE_AND_CHECK(_output, data); CpuState* state = thread->GetCpuState(); BVariant value; @@ -559,15 +583,15 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, char buffer[64]; data.SetToFormat("\t\t\t%5s:\t%s\n", reg->Name(), UiUtils::VariantToString(value, buffer, sizeof(buffer))); - _output << data; + WRITE_AND_CHECK(_output, data); } return B_OK; } -void -DebugReportGenerator::_DumpFunctionDisassembly(BString& _output, +status_t +DebugReportGenerator::_DumpFunctionDisassembly(BFile& _output, target_addr_t instructionPointer) { AutoLocker< ::Team> teamLocker(fTeam); @@ -579,8 +603,8 @@ DebugReportGenerator::_DumpFunctionDisassembly(BString& _output, if (error != B_OK) { data.SetToFormat("Unable to retrieve disassembly for IP %#" B_PRIx64 ": %s\n", instructionPointer, strerror(error)); - _output << data; - return; + WRITE_AND_CHECK(_output, data); + return B_OK; } DisassembledCode* code = instance->GetSourceCode(); @@ -599,18 +623,20 @@ DebugReportGenerator::_DumpFunctionDisassembly(BString& _output, case FUNCTION_SOURCE_LOADING: { teamLocker.Unlock(); - error = acquire_sem(fTeamDataSem); + do { + error = acquire_sem(fTeamDataSem); + } while (error == B_INTERRUPTED); if (error != B_OK) - return; + return error; teamLocker.Lock(); break; } default: - return; + return B_OK; } if (instance->SourceCodeState() == FUNCTION_SOURCE_UNAVAILABLE) - return; + return B_OK; error = fTeam->GetStatementAtAddress(instructionPointer, instance, statement); @@ -619,19 +645,25 @@ DebugReportGenerator::_DumpFunctionDisassembly(BString& _output, SourceLocation location = statement->StartSourceLocation(); - _output << "\t\t\tDisassembly:\n"; + data = "\t\t\tDisassembly:\n"; + WRITE_AND_CHECK(_output, data); for (int32 i = 0; i <= location.Line(); i++) { - _output << "\t\t\t\t" << code->LineAt(i); + data = "\t\t\t\t"; + data << code->LineAt(i); if (i == location.Line()) - _output << " <--"; - _output << "\n"; + data << " <--"; + data << "\n"; + WRITE_AND_CHECK(_output, data); } - _output << "\n"; + data = "\n"; + WRITE_AND_CHECK(_output, data); + + return B_OK; } -void -DebugReportGenerator::_DumpStackFrameMemory(BString& _output, +status_t +DebugReportGenerator::_DumpStackFrameMemory(BFile& _output, CpuState* state, target_addr_t framePointer, uint8 stackDirection) { target_addr_t startAddress; @@ -644,25 +676,29 @@ DebugReportGenerator::_DumpStackFrameMemory(BString& _output, endAddress = framePointer; } + status_t error; if (fCurrentBlock == NULL || !fCurrentBlock->Contains(startAddress)) { fListener->InspectRequested(startAddress, this); - status_t result = B_OK; + error = B_OK; do { - result = acquire_sem(fTeamDataSem); - } while (result == B_INTERRUPTED); + error = acquire_sem(fTeamDataSem); + } while (error == B_INTERRUPTED); } - _output << "\t\t\tFrame memory:\n"; + BString data("\t\t\tFrame memory:\n"); + WRITE_AND_CHECK(_output, data); if (fBlockRetrievalStatus == B_OK) { - UiUtils::DumpMemory(_output, 4 , fCurrentBlock, startAddress, 1, 16, + data.Truncate(0L); + UiUtils::DumpMemory(data, 4, fCurrentBlock, startAddress, 1, 16, endAddress - startAddress); + WRITE_AND_CHECK(_output, data); } else { - BString data; data.SetToFormat("\t\t\t\tUnavailable (%s)\n", strerror( fBlockRetrievalStatus)); - _output += data; + WRITE_AND_CHECK(_output, data); } + return B_OK; } diff --git a/src/apps/debugger/controllers/DebugReportGenerator.h b/src/apps/debugger/controllers/DebugReportGenerator.h index 121bb5a20c..e88d62f2d7 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.h +++ b/src/apps/debugger/controllers/DebugReportGenerator.h @@ -17,7 +17,7 @@ class entry_ref; class Architecture; class AreaInfo; -class BString; +class BFile; class DebuggerInterface; class SemaphoreInfo; class StackFrame; @@ -65,16 +65,16 @@ private: private: status_t _GenerateReport(const entry_ref& outputPath); - status_t _GenerateReportHeader(BString& _output); - status_t _DumpLoadedImages(BString& _output); - status_t _DumpAreas(BString& _output); - status_t _DumpSemaphores(BString& _output); - status_t _DumpRunningThreads(BString& _output); - status_t _DumpDebuggedThreadInfo(BString& _output, + status_t _GenerateReportHeader(BFile& _output); + status_t _DumpLoadedImages(BFile& _output); + status_t _DumpAreas(BFile& _output); + status_t _DumpSemaphores(BFile& _output); + status_t _DumpRunningThreads(BFile& _output); + status_t _DumpDebuggedThreadInfo(BFile& _output, ::Thread* thread); - void _DumpFunctionDisassembly(BString& _output, + status_t _DumpFunctionDisassembly(BFile& _output, target_addr_t instructionPointer); - void _DumpStackFrameMemory(BString& _output, + status_t _DumpStackFrameMemory(BFile& _output, CpuState* state, target_addr_t framePointer, uint8 stackDirection);