/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2012-2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "UiUtils.h"
#include <ctype.h>
#include <stdio.h>
#include <DateTime.h>
#include <KernelExport.h>
#include <Path.h>
#include <String.h>
#include <Variant.h>
#include <vm_defs.h>
#include "FunctionInstance.h"
#include "Image.h"
#include "RangeList.h"
#include "SignalDispositionTypes.h"
#include "StackFrame.h"
#include "Team.h"
#include "TeamMemoryBlock.h"
#include "Thread.h"
#include "Type.h"
#include "Value.h"
#include "ValueNode.h"
/*static*/ const char*
UiUtils::ThreadStateToString(int state, int stoppedReason)
{
switch (state) {
case THREAD_STATE_RUNNING:
return "Running";
case THREAD_STATE_STOPPED:
break;
case THREAD_STATE_UNKNOWN:
default:
return "?";
}
// thread is stopped -- get the reason
switch (stoppedReason) {
case THREAD_STOPPED_DEBUGGER_CALL:
return "Call";
case THREAD_STOPPED_EXCEPTION:
return "Exception";
case THREAD_STOPPED_BREAKPOINT:
case THREAD_STOPPED_WATCHPOINT:
case THREAD_STOPPED_SINGLE_STEP:
case THREAD_STOPPED_DEBUGGED:
case THREAD_STOPPED_UNKNOWN:
default:
return "Debugged";
}
}
/*static*/ const char*
UiUtils::VariantToString(const BVariant& value, char* buffer,
size_t bufferSize)
{
if (!value.IsNumber())
return value.ToString();
switch (value.Type()) {
case B_FLOAT_TYPE:
case B_DOUBLE_TYPE:
snprintf(buffer, bufferSize, "%.3g", value.ToDouble());
break;
case B_INT8_TYPE:
case B_UINT8_TYPE:
snprintf(buffer, bufferSize, "0x%02x", value.ToUInt8());
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
snprintf(buffer, bufferSize, "0x%04x", value.ToUInt16());
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
snprintf(buffer, bufferSize, "0x%08" B_PRIx32,
value.ToUInt32());
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
default:
snprintf(buffer, bufferSize, "0x%016" B_PRIx64,
value.ToUInt64());
break;
}
return buffer;
}
/*static*/ const char*
UiUtils::FunctionNameForFrame(StackFrame* frame, char* buffer,
size_t bufferSize)
{
Image* image = frame->GetImage();
FunctionInstance* function = frame->Function();
if (image == NULL && function == NULL) {
snprintf(buffer, bufferSize, "?");
return buffer;
}
BString name;
target_addr_t baseAddress;
if (function != NULL) {
name = function->PrettyName();
baseAddress = function->Address();
} else {
name = image->Name();
baseAddress = image->Info().TextBase();
}
snprintf(buffer, bufferSize, "%s + %#" B_PRIx64,
name.String(), frame->InstructionPointer() - baseAddress);
return buffer;
}
/*static*/ const char*
UiUtils::ImageTypeToString(image_type type, char* buffer, size_t bufferSize)
{
switch (type) {
case B_APP_IMAGE:
snprintf(buffer, bufferSize, "app");
break;
case B_LIBRARY_IMAGE:
snprintf(buffer, bufferSize, "lib");
break;
case B_ADD_ON_IMAGE:
snprintf(buffer, bufferSize, "add-on");
break;
case B_SYSTEM_IMAGE:
snprintf(buffer, bufferSize, "system");
break;
default:
snprintf(buffer, bufferSize, "unknown");
break;
}
return buffer;
}
/*static*/ const char*
UiUtils::AreaLockingFlagsToString(uint32 flags, char* buffer,
size_t bufferSize)
{
switch (flags) {
case B_NO_LOCK:
snprintf(buffer, bufferSize, "none");
break;
case B_LAZY_LOCK:
snprintf(buffer, bufferSize, "lazy");
break;
case B_FULL_LOCK:
snprintf(buffer, bufferSize, "full");
break;
case B_CONTIGUOUS:
snprintf(buffer, bufferSize, "contiguous");
break;
case B_LOMEM:
snprintf(buffer, bufferSize, "lo-mem");
break;
case B_32_BIT_FULL_LOCK:
snprintf(buffer, bufferSize, "32-bit full");
break;
case B_32_BIT_CONTIGUOUS:
snprintf(buffer, bufferSize, "32-bit contig.");
break;
default:
snprintf(buffer, bufferSize, "unknown");
break;
}
return buffer;
}
/*static*/ const BString&
UiUtils::AreaProtectionFlagsToString(uint32 protection, BString& _output)
{
#undef ADD_AREA_FLAG_IF_PRESENT
#define ADD_AREA_FLAG_IF_PRESENT(flag, protection, name, output, missing)\
if ((protection & flag) != 0) { \
_output += name; \
protection &= ~flag; \
} else \
_output += missing; \
_output.Truncate(0);
uint32 userFlags = protection & B_USER_PROTECTION;
bool userProtectionPresent = userFlags != 0;
ADD_AREA_FLAG_IF_PRESENT(B_READ_AREA, protection, "r", _output,
userProtectionPresent ? "-" : " ");
ADD_AREA_FLAG_IF_PRESENT(B_WRITE_AREA, protection, "w", _output,
userProtectionPresent ? "-" : " ");
ADD_AREA_FLAG_IF_PRESENT(B_EXECUTE_AREA, protection, "x", _output,
userProtectionPresent ? "-" : " ");
// if the user versions of these flags are present,
// filter out their kernel equivalents since they're implied.
if ((userFlags & B_READ_AREA) != 0)
protection &= ~B_KERNEL_READ_AREA;
if ((userFlags & B_WRITE_AREA) != 0)
protection &= ~B_KERNEL_WRITE_AREA;
if ((userFlags & B_EXECUTE_AREA) != 0)
protection &= ~B_KERNEL_EXECUTE_AREA;
if ((protection & B_KERNEL_PROTECTION) != 0) {
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_READ_AREA, protection, "r",
_output, "-");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_WRITE_AREA, protection, "w",
_output, "-");
ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_EXECUTE_AREA, protection, "x",
_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, "");
if (protection != 0) {
char buffer[32];
snprintf(buffer, sizeof(buffer), ", u:(%#04" B_PRIx32 ")",
protection);
_output += buffer;
}
return _output;
}
/*static*/ const char*
UiUtils::ReportNameForTeam(::Team* team, char* buffer, size_t bufferSize)
{
BPath teamPath(team->Name());
BDateTime currentTime;
currentTime.SetTime_t(time(NULL));
snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02"
B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02"
B_PRId32 ".report", teamPath.Leaf(), team->ID(),
currentTime.Date().Day(), currentTime.Date().Month(),
currentTime.Date().Year(), currentTime.Time().Hour(),
currentTime.Time().Minute(), currentTime.Time().Second());
return buffer;
}
/*static*/ const char*
UiUtils::CoreFileNameForTeam(::Team* team, char* buffer, size_t bufferSize)
{
BPath teamPath(team->Name());
BDateTime currentTime;
currentTime.SetTime_t(time(NULL));
snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02"
B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02"
B_PRId32 ".core", teamPath.Leaf(), team->ID(),
currentTime.Date().Day(), currentTime.Date().Month(),
currentTime.Date().Year(), currentTime.Time().Hour(),
currentTime.Time().Minute(), currentTime.Time().Second());
return buffer;
}
/*static*/ void
UiUtils::PrintValueNodeGraph(BString& _output, ValueNodeChild* child,
int32 indentLevel, int32 maxDepth)
{
_output.Append('\t', indentLevel);
_output << child->Name();
ValueNode* node = child->Node();
if (node == NULL) {
_output << ": Unavailable\n";
return;
}
if (node->GetType()->Kind() != TYPE_COMPOUND) {
_output << ": ";
status_t resolutionState = node->LocationAndValueResolutionState();
if (resolutionState == VALUE_NODE_UNRESOLVED)
_output << "Unresolved";
else if (resolutionState == B_OK) {
Value* value = node->GetValue();
if (value != NULL) {
BString valueData;
value->ToString(valueData);
_output << valueData;
} else
_output << "Unavailable";
} else
_output << strerror(resolutionState);
}
if (maxDepth == 0 || node->CountChildren() == 0) {
_output << "\n";
return;
}
if (node->CountChildren() == 1
&& node->GetType()->ResolveRawType(false)->Kind() == TYPE_ADDRESS
&& node->ChildAt(0)->GetType()->ResolveRawType(false)->Kind()
== TYPE_COMPOUND) {
// for the case of a pointer to a compound type,
// we want to hide the intervening compound node and print
// the children directly.
node = node->ChildAt(0)->Node();
}
if (node != NULL) {
_output << " {\n";
for (int32 i = 0; i < node->CountChildren(); i++) {
// don't dump compound nodes if our depth limit won't allow
// us to traverse into their children anyways, and the top
// level node contains no data of intereest.
if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND
|| maxDepth > 1) {
PrintValueNodeGraph(_output, node->ChildAt(i),
indentLevel + 1, maxDepth - 1);
}
}
_output.Append('\t', indentLevel);
_output << "}\n";
} else
_output << "\n";
return;
}
/*static*/ void
UiUtils::DumpMemory(BString& _output, int32 indentLevel,
TeamMemoryBlock* block, target_addr_t address, int32 itemSize,
int32 displayWidth, int32 count)
{
BString data;
int32 j;
_output.Append('\t', indentLevel);
for (int32 i = 0; i < count; i++) {
if (!block->Contains(address + i * itemSize))
break;
uint8* value;
if ((i % displayWidth) == 0) {
int32 displayed = min_c(displayWidth, (count-i)) * itemSize;
if (i != 0) {
_output.Append("\n");
_output.Append('\t', indentLevel);
}
data.SetToFormat("[%#" B_PRIx64 "] ", address + i * itemSize);
_output += data;
char c;
for (j = 0; j < displayed; j++) {
c = *(block->Data() + address - block->BaseAddress()
+ (i * itemSize) + j);
if (!isprint(c))
c = '.';
_output += c;
}
if (count > displayWidth) {
// make sure the spacing in the last line is correct
for (j = displayed; j < displayWidth * itemSize; j++)
_output += ' ';
}
_output.Append(" ");
}
value = block->Data() + address - block->BaseAddress()
+ i * itemSize;
switch (itemSize) {
case 1:
data.SetToFormat(" %02" B_PRIx8, *(uint8*)value);
break;
case 2:
data.SetToFormat(" %04" B_PRIx16, *(uint16*)value);
break;
case 4:
data.SetToFormat(" %08" B_PRIx32, *(uint32*)value);
break;
case 8:
data.SetToFormat(" %016" B_PRIx64, *(uint64*)value);
break;
}
_output += data;
}
_output.Append("\n");
}
static status_t ParseRangeString(BString& rangeString, int32& lowerBound,
int32& upperBound)
{
lowerBound = atoi(rangeString.String());
int32 index = rangeString.FindFirst('-');
if (index >= 0) {
rangeString.Remove(0, index + 1);
upperBound = atoi(rangeString.String());
} else
upperBound = lowerBound;
if (lowerBound > upperBound)
return B_BAD_VALUE;
return B_OK;
}
/*static*/ status_t
UiUtils::ParseRangeExpression(const BString& rangeExpression, int32 lowerBound,
int32 upperBound, bool fixedRange, RangeList& _output)
{
if (rangeExpression.IsEmpty())
return B_BAD_DATA;
BString dataString = rangeExpression;
dataString.RemoveAll(" ");
// first, tokenize the range list to its constituent child ranges.
int32 index;
int32 lowValue;
int32 highValue;
BString tempRange;
while (!dataString.IsEmpty()) {
index = dataString.FindFirst(',');
if (index == 0)
return B_BAD_VALUE;
else if (index > 0) {
dataString.MoveInto(tempRange, 0, index);
dataString.Remove(0, 1);
} else {
tempRange = dataString;
dataString.Truncate(0);
}
status_t result = ParseRangeString(tempRange, lowValue, highValue);
if (result != B_OK)
return result;
if (fixedRange && (lowValue < lowerBound || highValue > upperBound))
return B_BAD_VALUE;
result = _output.AddRange(lowValue, highValue);
if (result != B_OK)
return result;
tempRange.Truncate(0);
}
return B_OK;
}
/*static*/ const char*
UiUtils::TypeCodeToString(type_code type)
{
switch (type) {
case B_INT8_TYPE:
return "int8";
case B_UINT8_TYPE:
return "uint8";
case B_INT16_TYPE:
return "int16";
case B_UINT16_TYPE:
return "uint16";
case B_INT32_TYPE:
return "int32";
case B_UINT32_TYPE:
return "uint32";
case B_INT64_TYPE:
return "int64";
case B_UINT64_TYPE:
return "uint64";
case B_FLOAT_TYPE:
return "float";
case B_DOUBLE_TYPE:
return "double";
case B_STRING_TYPE:
return "string";
default:
return "unknown";
}
}
template<typename T>
T GetSIMDValueAtOffset(char* data, int32 index)
{
return ((T*)data)[index];
}
static int32 GetSIMDFormatByteSize(uint32 format)
{
switch (format) {
case SIMD_RENDER_FORMAT_INT8:
return sizeof(char);
case SIMD_RENDER_FORMAT_INT16:
return sizeof(int16);
case SIMD_RENDER_FORMAT_INT32:
return sizeof(int32);
case SIMD_RENDER_FORMAT_INT64:
return sizeof(int64);
case SIMD_RENDER_FORMAT_FLOAT:
return sizeof(float);
case SIMD_RENDER_FORMAT_DOUBLE:
return sizeof(double);
}
return 0;
}
/*static*/
const BString&
UiUtils::FormatSIMDValue(const BVariant& value, uint32 bitSize,
uint32 format, BString& _output)
{
_output.SetTo("{");
char* data = (char*)value.ToPointer();
uint32 count = bitSize / (GetSIMDFormatByteSize(format) * 8);
for (uint32 i = 0; i < count; i ++) {
BString temp;
switch (format) {
case SIMD_RENDER_FORMAT_INT8:
temp.SetToFormat("%#" B_PRIx8,
GetSIMDValueAtOffset<uint8>(data, i));
break;
case SIMD_RENDER_FORMAT_INT16:
temp.SetToFormat("%#" B_PRIx16,
GetSIMDValueAtOffset<uint16>(data, i));
break;
case SIMD_RENDER_FORMAT_INT32:
temp.SetToFormat("%#" B_PRIx32,
GetSIMDValueAtOffset<uint32>(data, i));
break;
case SIMD_RENDER_FORMAT_INT64:
temp.SetToFormat("%#" B_PRIx64,
GetSIMDValueAtOffset<uint64>(data, i));
break;
case SIMD_RENDER_FORMAT_FLOAT:
temp.SetToFormat("%.3g",
(double)GetSIMDValueAtOffset<float>(data, i));
break;
case SIMD_RENDER_FORMAT_DOUBLE:
temp.SetToFormat("%.3g",
GetSIMDValueAtOffset<double>(data, i));
break;
}
_output += temp;
if (i < count - 1)
_output += ", ";
}
_output += "}";
return _output;
}
const char*
UiUtils::SignalNameToString(int32 signal, BString& _output)
{
#undef DEFINE_SIGNAL_STRING
#define DEFINE_SIGNAL_STRING(x) \
case x: \
_output = #x; \
return _output.String();
switch (signal) {
DEFINE_SIGNAL_STRING(SIGHUP)
DEFINE_SIGNAL_STRING(SIGINT)
DEFINE_SIGNAL_STRING(SIGQUIT)
DEFINE_SIGNAL_STRING(SIGILL)
DEFINE_SIGNAL_STRING(SIGCHLD)
DEFINE_SIGNAL_STRING(SIGABRT)
DEFINE_SIGNAL_STRING(SIGPIPE)
DEFINE_SIGNAL_STRING(SIGFPE)
DEFINE_SIGNAL_STRING(SIGKILL)
DEFINE_SIGNAL_STRING(SIGSTOP)
DEFINE_SIGNAL_STRING(SIGSEGV)
DEFINE_SIGNAL_STRING(SIGCONT)
DEFINE_SIGNAL_STRING(SIGTSTP)
DEFINE_SIGNAL_STRING(SIGALRM)
DEFINE_SIGNAL_STRING(SIGTERM)
DEFINE_SIGNAL_STRING(SIGTTIN)
DEFINE_SIGNAL_STRING(SIGTTOU)
DEFINE_SIGNAL_STRING(SIGUSR1)
DEFINE_SIGNAL_STRING(SIGUSR2)
DEFINE_SIGNAL_STRING(SIGWINCH)
DEFINE_SIGNAL_STRING(SIGKILLTHR)
DEFINE_SIGNAL_STRING(SIGTRAP)
DEFINE_SIGNAL_STRING(SIGPOLL)
DEFINE_SIGNAL_STRING(SIGPROF)
DEFINE_SIGNAL_STRING(SIGSYS)
DEFINE_SIGNAL_STRING(SIGURG)
DEFINE_SIGNAL_STRING(SIGVTALRM)
DEFINE_SIGNAL_STRING(SIGXCPU)
DEFINE_SIGNAL_STRING(SIGXFSZ)
DEFINE_SIGNAL_STRING(SIGBUS)
default:
break;
}
if (signal == SIGRTMIN)
_output = "SIGRTMIN";
else if (signal == SIGRTMAX)
_output = "SIGRTMAX";
else
_output.SetToFormat("SIGRTMIN+%" B_PRId32, signal - SIGRTMIN);
return _output.String();
}
const char*
UiUtils::SignalDispositionToString(int disposition)
{
switch (disposition) {
case SIGNAL_DISPOSITION_IGNORE:
return "Ignore";
case SIGNAL_DISPOSITION_STOP_AT_RECEIPT:
return "Stop at receipt";
case SIGNAL_DISPOSITION_STOP_AT_SIGNAL_HANDLER:
return "Stop at signal handler";
default:
break;
}
return "Unknown";
}
↑ V609 Divide by zero. Denominator range [0..64].