Rework report format as suggested in #9697.

- Areas, images and semaphores are now presented in a more readable
  tabular format.

- Areas: Columns now include base address, end address and size to
  make it easier to determine if e.g. an address easily falls within
  a given area, and are also sorted by base address. Protection flags
  and locking have been made more concise, with a corresponding key.
  Name has been moved to the last column to allow for a more compact
  format.

- Images: Name moved to last column for improved column formatting,
  purposes, and sorted by load address.

- Threads are now sorted such that all threads in exception states
  come at the tail end of the list, and the format has been revised
  to make them a bit easier to parse. State is only indicated if
  something other than running, along with any available exception
  state messages.
This commit is contained in:
Rene Gollent
2013-04-23 21:31:18 -04:00
parent 8386448172
commit 8b49cb7645
3 changed files with 165 additions and 79 deletions
@@ -248,22 +248,34 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output)
AutoLocker< ::Team> locker(fTeam); AutoLocker< ::Team> locker(fTeam);
_output << "\nLoaded Images:\n"; _output << "\nLoaded Images:\n";
BObjectList<Image> images;
BString data; BString data;
for (ImageList::ConstIterator it = fTeam->Images().GetIterator(); for (ImageList::ConstIterator it = fTeam->Images().GetIterator();
Image* image = it.Next();) { Image* image = it.Next();) {
images.AddItem(image);
}
images.SortItems(&_CompareImages);
Image* image = NULL;
data.SetToFormat("\tID\t\tText Base\tText End\tData Base\tData"
" End\tType\t\tName\n\t");
_output << data;
_output.Append('-', 80);
_output.Append("\n");
for (int32 i = 0; (image = images.ItemAt(i)) != NULL; i++) {
const ImageInfo& info = image->Info(); const ImageInfo& info = image->Info();
char buffer[32]; char buffer[32];
try { try {
target_addr_t textBase = info.TextBase(); target_addr_t textBase = info.TextBase();
target_addr_t dataBase = info.DataBase(); target_addr_t dataBase = info.DataBase();
data.SetToFormat("\t%s (%" B_PRId32 ", %s) " data.SetToFormat("\t%" B_PRId32 "\t0x%08" B_PRIx64 "\t"
"Text: %#08" B_PRIx64 " - %#08" B_PRIx64 ", Data: %#08" "0x%08" B_PRIx64 "\t0x%08" B_PRIx64 "\t0x%08" B_PRIx64 "\t"
B_PRIx64 " - %#08" B_PRIx64 "\n", info.Name().String(), "%-7s\t\t%s\n", info.ImageID(), textBase, textBase + info.TextSize(),
info.ImageID(), UiUtils::ImageTypeToString(info.Type(), dataBase, dataBase + info.DataSize(),
buffer, sizeof(buffer)), textBase, UiUtils::ImageTypeToString(info.Type(), buffer,
textBase + info.TextSize(), dataBase, sizeof(buffer)), info.Name().String());
dataBase + info.DataSize());
_output << data; _output << data;
} catch (...) { } catch (...) {
@@ -283,22 +295,27 @@ DebugReportGenerator::_DumpAreas(BString& _output)
if (result != B_OK) if (result != B_OK)
return result; return result;
areas.SortItems(&_CompareAreas);
_output << "\nAreas:\n"; _output << "\nAreas:\n";
BString data; BString data;
data.SetToFormat("\tID\t\tBase\t\tEnd\t\t\tSize (KiB)\tProtection\tLocking\t\t\t\tName\n\t");
_output << data;
_output.Append('-', 80);
_output.Append("\n");
AreaInfo* info; AreaInfo* info;
BString protectionBuffer; BString protectionBuffer;
char lockingBuffer[32]; char lockingBuffer[32];
for (int32 i = 0; (info = areas.ItemAt(i)) != NULL; i++) { for (int32 i = 0; (info = areas.ItemAt(i)) != NULL; i++) {
try { try {
data.SetToFormat("\t%s (%" B_PRId32 ") " data.SetToFormat("\t%" B_PRId32 "\t0x%08" B_PRIx64 "\t"
"Base: %#08" B_PRIx64 ", Size: %" B_PRId64 "0x%08" B_PRIx64 "\t%10" B_PRId64 "\t%-11s\t%-17s\t%s\n",
", RAM Size: %" B_PRId64 ",Locking: %s, Protection: %s\n", info->AreaID(), info->BaseAddress(), info->BaseAddress()
info->Name().String(), info->AreaID(), info->BaseAddress(), + info->Size(), info->Size() / 1024,
info->Size(), info->RamSize(),
UiUtils::AreaLockingFlagsToString(info->Lock(), lockingBuffer,
sizeof(lockingBuffer)),
UiUtils::AreaProtectionFlagsToString(info->Protection(), UiUtils::AreaProtectionFlagsToString(info->Protection(),
protectionBuffer).String()); protectionBuffer).String(),
UiUtils::AreaLockingFlagsToString(info->Lock(), lockingBuffer,
sizeof(lockingBuffer)), info->Name().String());
_output << data; _output << data;
} catch (...) { } catch (...) {
@@ -306,6 +323,9 @@ DebugReportGenerator::_DumpAreas(BString& _output)
} }
} }
_output << "\nProtection Flags: r - read, w - write, x - execute, "
"s - stack, o - overcommit, c - cloneable, S - shared, k - kernel\n";
return B_OK; return B_OK;
} }
@@ -318,15 +338,20 @@ DebugReportGenerator::_DumpSemaphores(BString& _output)
if (result != B_OK) if (result != B_OK)
return result; return result;
semaphores.SortItems(&_CompareSemaphores);
_output << "\nSemaphores:\n"; _output << "\nSemaphores:\n";
BString data; BString data;
data.SetToFormat("\tID\t\tCount\tLast Holder\t\tName\n\t");
_output << data;
_output.Append('-', 80);
_output.Append("\n");
SemaphoreInfo* info; SemaphoreInfo* info;
for (int32 i = 0; (info = semaphores.ItemAt(i)) != NULL; i++) { for (int32 i = 0; (info = semaphores.ItemAt(i)) != NULL; i++) {
try { try {
data.SetToFormat("\t%s (%" B_PRId32 ") " data.SetToFormat("\t%" B_PRId32 "\t%5" B_PRId32 "\t%11" B_PRId32
"Count: %" B_PRId32 ", Latest Holding Thread: %" B_PRId32 "\n", "\t\t%s\n", info->SemID(), info->Count(),
info->Name().String(), info->SemID(), info->Count(), info->LatestHolder(), info->Name().String());
info->LatestHolder());
_output << data; _output << data;
} catch (...) { } catch (...) {
@@ -346,24 +371,30 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output)
_output << "\nActive Threads:\n"; _output << "\nActive Threads:\n";
BString data; BString data;
status_t result = B_OK; status_t result = B_OK;
BObjectList< ::Thread> threads;
::Thread* thread;
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator(); for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
::Thread* thread = it.Next();) { (thread = it.Next());) {
threads.AddItem(thread);
}
threads.SortItems(&_CompareThreads);
for (int32 i = 0; (thread = threads.ItemAt(i)) != NULL; i++) {
try { try {
data.SetToFormat("\t%s %s, id: %" B_PRId32", state: %s", data.SetToFormat("\tthread %" B_PRId32 ": %s %s", thread->ID(),
thread->Name(), thread->IsMainThread() thread->Name(), thread->IsMainThread()
? "(main)" : "", thread->ID(), ? "(main)" : "");
UiUtils::ThreadStateToString(thread->State(),
thread->StoppedReason()));
if (thread->State() == THREAD_STATE_STOPPED) {
const BString& stoppedInfo = thread->StoppedReasonInfo();
if (stoppedInfo.Length() != 0)
data << " (" << stoppedInfo << ")";
}
_output << data << "\n"; _output << data << "\n";
if (thread->State() == THREAD_STATE_STOPPED) { if (thread->State() == THREAD_STATE_STOPPED) {
data.SetToFormat("\t\tstate: %s",
UiUtils::ThreadStateToString(thread->State(),
thread->StoppedReason()));
const BString& stoppedInfo = thread->StoppedReasonInfo();
if (stoppedInfo.Length() != 0)
data << " (" << stoppedInfo << ")";
_output << data << "\n\n";
// we need to release our lock on the team here // we need to release our lock on the team here
// since we might need to block and wait // since we might need to block and wait
// on the stack trace. // on the stack trace.
@@ -554,3 +585,51 @@ DebugReportGenerator::_HandleMemoryBlockRetrieved(TeamMemoryBlock* block,
fCurrentBlock = block; fCurrentBlock = block;
release_sem(fTeamDataSem); release_sem(fTeamDataSem);
} }
/*static*/ int
DebugReportGenerator::_CompareAreas(const AreaInfo* a, const AreaInfo* b)
{
if (a->BaseAddress() < b->BaseAddress())
return -1;
return 1;
}
/*static*/ int
DebugReportGenerator::_CompareImages(const Image* a, const Image* b)
{
if (a->Info().TextBase() < b->Info().TextBase())
return -1;
return 1;
}
/*static*/ int
DebugReportGenerator::_CompareSemaphores(const SemaphoreInfo* a,
const SemaphoreInfo* b)
{
if (a->SemID() < b->SemID())
return -1;
return 1;
}
/*static*/ int
DebugReportGenerator::_CompareThreads(const ::Thread* a,
const ::Thread* b)
{
// sort stopped threads last, otherwise sort by thread ID
if (a->State() == b->State())
return a->ID() < b->ID() ? -1 : 1;
if (a->State() == THREAD_STATE_STOPPED && b->State()
!= THREAD_STATE_STOPPED) {
return 1;
}
return -1;
}
@@ -15,8 +15,10 @@
class entry_ref; class entry_ref;
class Architecture; class Architecture;
class AreaInfo;
class BString; class BString;
class DebuggerInterface; class DebuggerInterface;
class SemaphoreInfo;
class StackFrame; class StackFrame;
class Team; class Team;
class Thread; class Thread;
@@ -77,6 +79,13 @@ private:
void _HandleMemoryBlockRetrieved( void _HandleMemoryBlockRetrieved(
TeamMemoryBlock* block, status_t result); TeamMemoryBlock* block, status_t result);
static int _CompareAreas(const AreaInfo* a,
const AreaInfo* b);
static int _CompareImages(const Image* a, const Image* b);
static int _CompareSemaphores(const SemaphoreInfo* a,
const SemaphoreInfo* b);
static int _CompareThreads(const ::Thread* a,
const ::Thread* b);
private: private:
::Team* fTeam; ::Team* fTeam;
Architecture* fArchitecture; Architecture* fArchitecture;
@@ -129,19 +129,19 @@ UiUtils::ImageTypeToString(image_type type, char* buffer, size_t bufferSize)
{ {
switch (type) { switch (type) {
case B_APP_IMAGE: case B_APP_IMAGE:
snprintf(buffer, bufferSize, "Application"); snprintf(buffer, bufferSize, "app");
break; break;
case B_LIBRARY_IMAGE: case B_LIBRARY_IMAGE:
snprintf(buffer, bufferSize, "Library"); snprintf(buffer, bufferSize, "lib");
break; break;
case B_ADD_ON_IMAGE: case B_ADD_ON_IMAGE:
snprintf(buffer, bufferSize, "Add-on"); snprintf(buffer, bufferSize, "add-on");
break; break;
case B_SYSTEM_IMAGE: case B_SYSTEM_IMAGE:
snprintf(buffer, bufferSize, "System"); snprintf(buffer, bufferSize, "system");
break; break;
default: default:
snprintf(buffer, bufferSize, "Unknown"); snprintf(buffer, bufferSize, "unknown");
break; break;
} }
@@ -155,28 +155,28 @@ UiUtils::AreaLockingFlagsToString(uint32 flags, char* buffer,
{ {
switch (flags) { switch (flags) {
case B_NO_LOCK: case B_NO_LOCK:
snprintf(buffer, bufferSize, "None"); snprintf(buffer, bufferSize, "none");
break; break;
case B_LAZY_LOCK: case B_LAZY_LOCK:
snprintf(buffer, bufferSize, "Lazy"); snprintf(buffer, bufferSize, "lazy");
break; break;
case B_FULL_LOCK: case B_FULL_LOCK:
snprintf(buffer, bufferSize, "Full"); snprintf(buffer, bufferSize, "full");
break; break;
case B_CONTIGUOUS: case B_CONTIGUOUS:
snprintf(buffer, bufferSize, "Contiguous"); snprintf(buffer, bufferSize, "contiguous");
break; break;
case B_LOMEM: case B_LOMEM:
snprintf(buffer, bufferSize, "Lo-mem"); snprintf(buffer, bufferSize, "lo-mem");
break; break;
case B_32_BIT_FULL_LOCK: case B_32_BIT_FULL_LOCK:
snprintf(buffer, bufferSize, "32-bit Full"); snprintf(buffer, bufferSize, "32-bit full");
break; break;
case B_32_BIT_CONTIGUOUS: case B_32_BIT_CONTIGUOUS:
snprintf(buffer, bufferSize, "32-bit Contiguous"); snprintf(buffer, bufferSize, "32-bit contiguous");
break; break;
default: default:
snprintf(buffer, bufferSize, "Unknown"); snprintf(buffer, bufferSize, "unknown");
break; break;
} }
@@ -188,56 +188,54 @@ UiUtils::AreaLockingFlagsToString(uint32 flags, char* buffer,
UiUtils::AreaProtectionFlagsToString(uint32 protection, BString& _output) UiUtils::AreaProtectionFlagsToString(uint32 protection, BString& _output)
{ {
#undef ADD_AREA_FLAG_IF_PRESENT #undef ADD_AREA_FLAG_IF_PRESENT
#define ADD_AREA_FLAG_IF_PRESENT(flag, protection, name, output) \ #define ADD_AREA_FLAG_IF_PRESENT(flag, protection, name, output, missing)\
if ((protection & flag) != 0) { \ if ((protection & flag) != 0) { \
_output += name; \ _output += name; \
protection &= ~flag; \ protection &= ~flag; \
} } else \
_output += missing; \
_output.Truncate(0); _output.Truncate(0);
uint32 userFlags = protection & B_USER_PROTECTION; uint32 userFlags = protection & B_USER_PROTECTION;
if ((protection & B_USER_PROTECTION) != 0) { bool userProtectionPresent = userFlags != 0;
ADD_AREA_FLAG_IF_PRESENT(B_READ_AREA, protection, "r", _output); ADD_AREA_FLAG_IF_PRESENT(B_READ_AREA, protection, "r", _output,
ADD_AREA_FLAG_IF_PRESENT(B_WRITE_AREA, protection, "w", _output); userProtectionPresent ? "-" : " ");
ADD_AREA_FLAG_IF_PRESENT(B_EXECUTE_AREA, protection, "x", _output); ADD_AREA_FLAG_IF_PRESENT(B_WRITE_AREA, protection, "w", _output,
ADD_AREA_FLAG_IF_PRESENT(B_STACK_AREA, protection, "s", _output); userProtectionPresent ? "-" : " ");
ADD_AREA_FLAG_IF_PRESENT(B_OVERCOMMITTING_AREA, protection, " overcommitting", ADD_AREA_FLAG_IF_PRESENT(B_EXECUTE_AREA, protection, "x", _output,
_output); userProtectionPresent ? "-" : " ");
_output += ", ";
// if the user versions of these flags are present, // if the user versions of these flags are present,
// filter out their kernel equivalents since they're implied. // filter out their kernel equivalents since they're implied.
if ((userFlags & B_READ_AREA) != 0) if ((userFlags & B_READ_AREA) != 0)
protection &= ~B_KERNEL_READ_AREA; protection &= ~B_KERNEL_READ_AREA;
if ((userFlags & B_WRITE_AREA) != 0) if ((userFlags & B_WRITE_AREA) != 0)
protection &= ~B_KERNEL_WRITE_AREA; protection &= ~B_KERNEL_WRITE_AREA;
if ((userFlags & B_EXECUTE_AREA) != 0) if ((userFlags & B_EXECUTE_AREA) != 0)
protection &= ~B_KERNEL_EXECUTE_AREA; protection &= ~B_KERNEL_EXECUTE_AREA;
if ((userFlags & B_STACK_AREA) != 0)
protection &= ~B_KERNEL_STACK_AREA; if ((protection & B_KERNEL_PROTECTION) != 0) {
} ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_READ_AREA, protection, "r",
if ((protection & B_KERNEL_AREA_FLAGS) != 0) { _output, "-");
_output += "kernel:";
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_READ_AREA, protection, "r", _output);
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_WRITE_AREA, protection, "w", ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_WRITE_AREA, protection, "w",
_output); _output, "-");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_EXECUTE_AREA, protection, "x", ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_EXECUTE_AREA, protection, "x",
_output); _output, "-");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_STACK_AREA, protection, "s",
_output);
ADD_AREA_FLAG_IF_PRESENT(B_USER_CLONEABLE_AREA, protection, " cloneable",
_output);
ADD_AREA_FLAG_IF_PRESENT(B_SHARED_AREA, protection, " shared", _output);
_output += ", ";
} }
ADD_AREA_FLAG_IF_PRESENT(B_STACK_AREA, protection, "s", _output, "");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_STACK_AREA, protection, "s", _output, "");
ADD_AREA_FLAG_IF_PRESENT(B_OVERCOMMITTING_AREA, protection, _output, "o",
"");
ADD_AREA_FLAG_IF_PRESENT(B_SHARED_AREA, protection, "S", _output, "");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_AREA, protection, "k", _output, "");
if (protection != 0) { if (protection != 0) {
char buffer[32]; char buffer[32];
snprintf(buffer, sizeof(buffer), " Unknown (%#04" B_PRIx32 ")", snprintf(buffer, sizeof(buffer), ", u:(%#04" B_PRIx32 ")",
protection); protection);
_output += buffer; _output += buffer;
} else if (!_output.IsEmpty()) }
_output.Truncate(_output.Length() - 2);
return _output; return _output;
} }