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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user