headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / debugger / user_interface / util / UiUtils.cpp
blob848981f3a8c37e83d89c44236fa7f1590a92cb1b
1 /*
2 * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "UiUtils.h"
10 #include <ctype.h>
11 #include <stdio.h>
13 #include <DateTime.h>
14 #include <KernelExport.h>
15 #include <Path.h>
16 #include <String.h>
17 #include <Variant.h>
19 #include <vm_defs.h>
21 #include "FunctionInstance.h"
22 #include "Image.h"
23 #include "RangeList.h"
24 #include "SignalDispositionTypes.h"
25 #include "StackFrame.h"
26 #include "Team.h"
27 #include "TeamMemoryBlock.h"
28 #include "Thread.h"
29 #include "Type.h"
30 #include "Value.h"
31 #include "ValueNode.h"
34 /*static*/ const char*
35 UiUtils::ThreadStateToString(int state, int stoppedReason)
37 switch (state) {
38 case THREAD_STATE_RUNNING:
39 return "Running";
40 case THREAD_STATE_STOPPED:
41 break;
42 case THREAD_STATE_UNKNOWN:
43 default:
44 return "?";
47 // thread is stopped -- get the reason
48 switch (stoppedReason) {
49 case THREAD_STOPPED_DEBUGGER_CALL:
50 return "Call";
51 case THREAD_STOPPED_EXCEPTION:
52 return "Exception";
53 case THREAD_STOPPED_BREAKPOINT:
54 case THREAD_STOPPED_WATCHPOINT:
55 case THREAD_STOPPED_SINGLE_STEP:
56 case THREAD_STOPPED_DEBUGGED:
57 case THREAD_STOPPED_UNKNOWN:
58 default:
59 return "Debugged";
64 /*static*/ const char*
65 UiUtils::VariantToString(const BVariant& value, char* buffer,
66 size_t bufferSize)
68 if (!value.IsNumber())
69 return value.ToString();
71 switch (value.Type()) {
72 case B_FLOAT_TYPE:
73 case B_DOUBLE_TYPE:
74 snprintf(buffer, bufferSize, "%.3g", value.ToDouble());
75 break;
76 case B_INT8_TYPE:
77 case B_UINT8_TYPE:
78 snprintf(buffer, bufferSize, "0x%02x", value.ToUInt8());
79 break;
80 case B_INT16_TYPE:
81 case B_UINT16_TYPE:
82 snprintf(buffer, bufferSize, "0x%04x", value.ToUInt16());
83 break;
84 case B_INT32_TYPE:
85 case B_UINT32_TYPE:
86 snprintf(buffer, bufferSize, "0x%08" B_PRIx32,
87 value.ToUInt32());
88 break;
89 case B_INT64_TYPE:
90 case B_UINT64_TYPE:
91 default:
92 snprintf(buffer, bufferSize, "0x%016" B_PRIx64,
93 value.ToUInt64());
94 break;
97 return buffer;
101 /*static*/ const char*
102 UiUtils::FunctionNameForFrame(StackFrame* frame, char* buffer,
103 size_t bufferSize)
105 Image* image = frame->GetImage();
106 FunctionInstance* function = frame->Function();
107 if (image == NULL && function == NULL) {
108 snprintf(buffer, bufferSize, "?");
109 return buffer;
112 BString name;
113 target_addr_t baseAddress;
114 if (function != NULL) {
115 name = function->PrettyName();
116 baseAddress = function->Address();
117 } else {
118 name = image->Name();
119 baseAddress = image->Info().TextBase();
122 snprintf(buffer, bufferSize, "%s + %#" B_PRIx64,
123 name.String(), frame->InstructionPointer() - baseAddress);
125 return buffer;
129 /*static*/ const char*
130 UiUtils::ImageTypeToString(image_type type, char* buffer, size_t bufferSize)
132 switch (type) {
133 case B_APP_IMAGE:
134 snprintf(buffer, bufferSize, "app");
135 break;
136 case B_LIBRARY_IMAGE:
137 snprintf(buffer, bufferSize, "lib");
138 break;
139 case B_ADD_ON_IMAGE:
140 snprintf(buffer, bufferSize, "add-on");
141 break;
142 case B_SYSTEM_IMAGE:
143 snprintf(buffer, bufferSize, "system");
144 break;
145 default:
146 snprintf(buffer, bufferSize, "unknown");
147 break;
150 return buffer;
154 /*static*/ const char*
155 UiUtils::AreaLockingFlagsToString(uint32 flags, char* buffer,
156 size_t bufferSize)
158 switch (flags) {
159 case B_NO_LOCK:
160 snprintf(buffer, bufferSize, "none");
161 break;
162 case B_LAZY_LOCK:
163 snprintf(buffer, bufferSize, "lazy");
164 break;
165 case B_FULL_LOCK:
166 snprintf(buffer, bufferSize, "full");
167 break;
168 case B_CONTIGUOUS:
169 snprintf(buffer, bufferSize, "contiguous");
170 break;
171 case B_LOMEM:
172 snprintf(buffer, bufferSize, "lo-mem");
173 break;
174 case B_32_BIT_FULL_LOCK:
175 snprintf(buffer, bufferSize, "32-bit full");
176 break;
177 case B_32_BIT_CONTIGUOUS:
178 snprintf(buffer, bufferSize, "32-bit contig.");
179 break;
180 default:
181 snprintf(buffer, bufferSize, "unknown");
182 break;
185 return buffer;
189 /*static*/ const BString&
190 UiUtils::AreaProtectionFlagsToString(uint32 protection, BString& _output)
192 #undef ADD_AREA_FLAG_IF_PRESENT
193 #define ADD_AREA_FLAG_IF_PRESENT(flag, protection, name, output, missing)\
194 if ((protection & flag) != 0) { \
195 _output += name; \
196 protection &= ~flag; \
197 } else \
198 _output += missing; \
200 _output.Truncate(0);
201 uint32 userFlags = protection & B_USER_PROTECTION;
202 bool userProtectionPresent = userFlags != 0;
203 ADD_AREA_FLAG_IF_PRESENT(B_READ_AREA, protection, "r", _output,
204 userProtectionPresent ? "-" : " ");
205 ADD_AREA_FLAG_IF_PRESENT(B_WRITE_AREA, protection, "w", _output,
206 userProtectionPresent ? "-" : " ");
207 ADD_AREA_FLAG_IF_PRESENT(B_EXECUTE_AREA, protection, "x", _output,
208 userProtectionPresent ? "-" : " ");
210 // if the user versions of these flags are present,
211 // filter out their kernel equivalents since they're implied.
212 if ((userFlags & B_READ_AREA) != 0)
213 protection &= ~B_KERNEL_READ_AREA;
214 if ((userFlags & B_WRITE_AREA) != 0)
215 protection &= ~B_KERNEL_WRITE_AREA;
216 if ((userFlags & B_EXECUTE_AREA) != 0)
217 protection &= ~B_KERNEL_EXECUTE_AREA;
219 if ((protection & B_KERNEL_PROTECTION) != 0) {
220 ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_READ_AREA, protection, "r",
221 _output, "-");
222 ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_WRITE_AREA, protection, "w",
223 _output, "-");
224 ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_EXECUTE_AREA, protection, "x",
225 _output, "-");
228 ADD_AREA_FLAG_IF_PRESENT(B_STACK_AREA, protection, "s", _output, "");
229 ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_STACK_AREA, protection, "s", _output, "");
230 ADD_AREA_FLAG_IF_PRESENT(B_OVERCOMMITTING_AREA, protection, _output, "o",
231 "");
232 ADD_AREA_FLAG_IF_PRESENT(B_SHARED_AREA, protection, "S", _output, "");
233 ADD_AREA_FLAG_IF_PRESENT(B_KERNEL_AREA, protection, "k", _output, "");
235 if (protection != 0) {
236 char buffer[32];
237 snprintf(buffer, sizeof(buffer), ", u:(%#04" B_PRIx32 ")",
238 protection);
239 _output += buffer;
242 return _output;
246 /*static*/ const char*
247 UiUtils::ReportNameForTeam(::Team* team, char* buffer, size_t bufferSize)
249 BPath teamPath(team->Name());
250 BDateTime currentTime;
251 currentTime.SetTime_t(time(NULL));
252 snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02"
253 B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02"
254 B_PRId32 ".report", teamPath.Leaf(), team->ID(),
255 currentTime.Date().Day(), currentTime.Date().Month(),
256 currentTime.Date().Year(), currentTime.Time().Hour(),
257 currentTime.Time().Minute(), currentTime.Time().Second());
259 return buffer;
263 /*static*/ const char*
264 UiUtils::CoreFileNameForTeam(::Team* team, char* buffer, size_t bufferSize)
266 BPath teamPath(team->Name());
267 BDateTime currentTime;
268 currentTime.SetTime_t(time(NULL));
269 snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02"
270 B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02"
271 B_PRId32 ".core", teamPath.Leaf(), team->ID(),
272 currentTime.Date().Day(), currentTime.Date().Month(),
273 currentTime.Date().Year(), currentTime.Time().Hour(),
274 currentTime.Time().Minute(), currentTime.Time().Second());
276 return buffer;
281 /*static*/ void
282 UiUtils::PrintValueNodeGraph(BString& _output, ValueNodeChild* child,
283 int32 indentLevel, int32 maxDepth)
285 _output.Append('\t', indentLevel);
286 _output << child->Name();
288 ValueNode* node = child->Node();
289 if (node == NULL) {
290 _output << ": Unavailable\n";
291 return;
294 if (node->GetType()->Kind() != TYPE_COMPOUND) {
295 _output << ": ";
296 status_t resolutionState = node->LocationAndValueResolutionState();
297 if (resolutionState == VALUE_NODE_UNRESOLVED)
298 _output << "Unresolved";
299 else if (resolutionState == B_OK) {
300 Value* value = node->GetValue();
301 if (value != NULL) {
302 BString valueData;
303 value->ToString(valueData);
304 _output << valueData;
305 } else
306 _output << "Unavailable";
307 } else
308 _output << strerror(resolutionState);
311 if (maxDepth == 0 || node->CountChildren() == 0) {
312 _output << "\n";
313 return;
316 if (node->CountChildren() == 1
317 && node->GetType()->ResolveRawType(false)->Kind() == TYPE_ADDRESS
318 && node->ChildAt(0)->GetType()->ResolveRawType(false)->Kind()
319 == TYPE_COMPOUND) {
320 // for the case of a pointer to a compound type,
321 // we want to hide the intervening compound node and print
322 // the children directly.
323 node = node->ChildAt(0)->Node();
326 if (node != NULL) {
327 _output << " {\n";
329 for (int32 i = 0; i < node->CountChildren(); i++) {
330 // don't dump compound nodes if our depth limit won't allow
331 // us to traverse into their children anyways, and the top
332 // level node contains no data of intereest.
333 if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND
334 || maxDepth > 1) {
335 PrintValueNodeGraph(_output, node->ChildAt(i),
336 indentLevel + 1, maxDepth - 1);
339 _output.Append('\t', indentLevel);
340 _output << "}\n";
341 } else
342 _output << "\n";
344 return;
348 /*static*/ void
349 UiUtils::DumpMemory(BString& _output, int32 indentLevel,
350 TeamMemoryBlock* block, target_addr_t address, int32 itemSize,
351 int32 displayWidth, int32 count)
353 BString data;
355 int32 j;
356 _output.Append('\t', indentLevel);
357 for (int32 i = 0; i < count; i++) {
358 if (!block->Contains(address + i * itemSize))
359 break;
361 uint8* value;
363 if ((i % displayWidth) == 0) {
364 int32 displayed = min_c(displayWidth, (count-i)) * itemSize;
365 if (i != 0) {
366 _output.Append("\n");
367 _output.Append('\t', indentLevel);
370 data.SetToFormat("[%#" B_PRIx64 "] ", address + i * itemSize);
371 _output += data;
372 char c;
373 for (j = 0; j < displayed; j++) {
374 c = *(block->Data() + address - block->BaseAddress()
375 + (i * itemSize) + j);
376 if (!isprint(c))
377 c = '.';
379 _output += c;
381 if (count > displayWidth) {
382 // make sure the spacing in the last line is correct
383 for (j = displayed; j < displayWidth * itemSize; j++)
384 _output += ' ';
386 _output.Append(" ");
389 value = block->Data() + address - block->BaseAddress()
390 + i * itemSize;
392 switch (itemSize) {
393 case 1:
394 data.SetToFormat(" %02" B_PRIx8, *(uint8*)value);
395 break;
396 case 2:
397 data.SetToFormat(" %04" B_PRIx16, *(uint16*)value);
398 break;
399 case 4:
400 data.SetToFormat(" %08" B_PRIx32, *(uint32*)value);
401 break;
402 case 8:
403 data.SetToFormat(" %016" B_PRIx64, *(uint64*)value);
404 break;
407 _output += data;
410 _output.Append("\n");
414 static status_t ParseRangeString(BString& rangeString, int32& lowerBound,
415 int32& upperBound)
417 lowerBound = atoi(rangeString.String());
418 int32 index = rangeString.FindFirst('-');
419 if (index >= 0) {
420 rangeString.Remove(0, index + 1);
421 upperBound = atoi(rangeString.String());
422 } else
423 upperBound = lowerBound;
425 if (lowerBound > upperBound)
426 return B_BAD_VALUE;
428 return B_OK;
432 /*static*/ status_t
433 UiUtils::ParseRangeExpression(const BString& rangeExpression, int32 lowerBound,
434 int32 upperBound, bool fixedRange, RangeList& _output)
436 if (rangeExpression.IsEmpty())
437 return B_BAD_DATA;
439 BString dataString = rangeExpression;
440 dataString.RemoveAll(" ");
442 // first, tokenize the range list to its constituent child ranges.
443 int32 index;
444 int32 lowValue;
445 int32 highValue;
446 BString tempRange;
447 while (!dataString.IsEmpty()) {
448 index = dataString.FindFirst(',');
449 if (index == 0)
450 return B_BAD_VALUE;
451 else if (index > 0) {
452 dataString.MoveInto(tempRange, 0, index);
453 dataString.Remove(0, 1);
454 } else {
455 tempRange = dataString;
456 dataString.Truncate(0);
459 status_t result = ParseRangeString(tempRange, lowValue, highValue);
460 if (result != B_OK)
461 return result;
464 if (fixedRange && (lowValue < lowerBound || highValue > upperBound))
465 return B_BAD_VALUE;
467 result = _output.AddRange(lowValue, highValue);
468 if (result != B_OK)
469 return result;
471 tempRange.Truncate(0);
474 return B_OK;
478 /*static*/ const char*
479 UiUtils::TypeCodeToString(type_code type)
481 switch (type) {
482 case B_INT8_TYPE:
483 return "int8";
484 case B_UINT8_TYPE:
485 return "uint8";
486 case B_INT16_TYPE:
487 return "int16";
488 case B_UINT16_TYPE:
489 return "uint16";
490 case B_INT32_TYPE:
491 return "int32";
492 case B_UINT32_TYPE:
493 return "uint32";
494 case B_INT64_TYPE:
495 return "int64";
496 case B_UINT64_TYPE:
497 return "uint64";
498 case B_FLOAT_TYPE:
499 return "float";
500 case B_DOUBLE_TYPE:
501 return "double";
502 case B_STRING_TYPE:
503 return "string";
504 default:
505 return "unknown";
510 template<typename T>
511 T GetSIMDValueAtOffset(char* data, int32 index)
513 return ((T*)data)[index];
517 static int32 GetSIMDFormatByteSize(uint32 format)
519 switch (format) {
520 case SIMD_RENDER_FORMAT_INT8:
521 return sizeof(char);
522 case SIMD_RENDER_FORMAT_INT16:
523 return sizeof(int16);
524 case SIMD_RENDER_FORMAT_INT32:
525 return sizeof(int32);
526 case SIMD_RENDER_FORMAT_INT64:
527 return sizeof(int64);
528 case SIMD_RENDER_FORMAT_FLOAT:
529 return sizeof(float);
530 case SIMD_RENDER_FORMAT_DOUBLE:
531 return sizeof(double);
534 return 0;
538 /*static*/
539 const BString&
540 UiUtils::FormatSIMDValue(const BVariant& value, uint32 bitSize,
541 uint32 format, BString& _output)
543 _output.SetTo("{");
544 char* data = (char*)value.ToPointer();
545 uint32 count = bitSize / (GetSIMDFormatByteSize(format) * 8);
546 for (uint32 i = 0; i < count; i ++) {
547 BString temp;
548 switch (format) {
549 case SIMD_RENDER_FORMAT_INT8:
550 temp.SetToFormat("%#" B_PRIx8,
551 GetSIMDValueAtOffset<uint8>(data, i));
552 break;
553 case SIMD_RENDER_FORMAT_INT16:
554 temp.SetToFormat("%#" B_PRIx16,
555 GetSIMDValueAtOffset<uint16>(data, i));
556 break;
557 case SIMD_RENDER_FORMAT_INT32:
558 temp.SetToFormat("%#" B_PRIx32,
559 GetSIMDValueAtOffset<uint32>(data, i));
560 break;
561 case SIMD_RENDER_FORMAT_INT64:
562 temp.SetToFormat("%#" B_PRIx64,
563 GetSIMDValueAtOffset<uint64>(data, i));
564 break;
565 case SIMD_RENDER_FORMAT_FLOAT:
566 temp.SetToFormat("%.3g",
567 (double)GetSIMDValueAtOffset<float>(data, i));
568 break;
569 case SIMD_RENDER_FORMAT_DOUBLE:
570 temp.SetToFormat("%.3g",
571 GetSIMDValueAtOffset<double>(data, i));
572 break;
574 _output += temp;
575 if (i < count - 1)
576 _output += ", ";
578 _output += "}";
580 return _output;
584 const char*
585 UiUtils::SignalNameToString(int32 signal, BString& _output)
587 #undef DEFINE_SIGNAL_STRING
588 #define DEFINE_SIGNAL_STRING(x) \
589 case x: \
590 _output = #x; \
591 return _output.String();
593 switch (signal) {
594 DEFINE_SIGNAL_STRING(SIGHUP)
595 DEFINE_SIGNAL_STRING(SIGINT)
596 DEFINE_SIGNAL_STRING(SIGQUIT)
597 DEFINE_SIGNAL_STRING(SIGILL)
598 DEFINE_SIGNAL_STRING(SIGCHLD)
599 DEFINE_SIGNAL_STRING(SIGABRT)
600 DEFINE_SIGNAL_STRING(SIGPIPE)
601 DEFINE_SIGNAL_STRING(SIGFPE)
602 DEFINE_SIGNAL_STRING(SIGKILL)
603 DEFINE_SIGNAL_STRING(SIGSTOP)
604 DEFINE_SIGNAL_STRING(SIGSEGV)
605 DEFINE_SIGNAL_STRING(SIGCONT)
606 DEFINE_SIGNAL_STRING(SIGTSTP)
607 DEFINE_SIGNAL_STRING(SIGALRM)
608 DEFINE_SIGNAL_STRING(SIGTERM)
609 DEFINE_SIGNAL_STRING(SIGTTIN)
610 DEFINE_SIGNAL_STRING(SIGTTOU)
611 DEFINE_SIGNAL_STRING(SIGUSR1)
612 DEFINE_SIGNAL_STRING(SIGUSR2)
613 DEFINE_SIGNAL_STRING(SIGWINCH)
614 DEFINE_SIGNAL_STRING(SIGKILLTHR)
615 DEFINE_SIGNAL_STRING(SIGTRAP)
616 DEFINE_SIGNAL_STRING(SIGPOLL)
617 DEFINE_SIGNAL_STRING(SIGPROF)
618 DEFINE_SIGNAL_STRING(SIGSYS)
619 DEFINE_SIGNAL_STRING(SIGURG)
620 DEFINE_SIGNAL_STRING(SIGVTALRM)
621 DEFINE_SIGNAL_STRING(SIGXCPU)
622 DEFINE_SIGNAL_STRING(SIGXFSZ)
623 DEFINE_SIGNAL_STRING(SIGBUS)
624 default:
625 break;
628 if (signal == SIGRTMIN)
629 _output = "SIGRTMIN";
630 else if (signal == SIGRTMAX)
631 _output = "SIGRTMAX";
632 else
633 _output.SetToFormat("SIGRTMIN+%" B_PRId32, signal - SIGRTMIN);
635 return _output.String();
639 const char*
640 UiUtils::SignalDispositionToString(int disposition)
642 switch (disposition) {
643 case SIGNAL_DISPOSITION_IGNORE:
644 return "Ignore";
645 case SIGNAL_DISPOSITION_STOP_AT_RECEIPT:
646 return "Stop at receipt";
647 case SIGNAL_DISPOSITION_STOP_AT_SIGNAL_HANDLER:
648 return "Stop at signal handler";
649 default:
650 break;
653 return "Unknown";