1/* 2 * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2012, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include "UiUtils.h" 9 10#include <ctype.h> 11#include <stdio.h> 12 13#include <DateTime.h> 14#include <Path.h> 15#include <String.h> 16#include <Variant.h> 17 18#include "FunctionInstance.h" 19#include "Image.h" 20#include "StackFrame.h" 21#include "Team.h" 22#include "TeamMemoryBlock.h" 23#include "Thread.h" 24#include "Type.h" 25#include "Value.h" 26#include "ValueNode.h" 27 28 29/*static*/ const char* 30UiUtils::ThreadStateToString(int state, int stoppedReason) 31{ 32 switch (state) { 33 case THREAD_STATE_RUNNING: 34 return "Running"; 35 case THREAD_STATE_STOPPED: 36 break; 37 case THREAD_STATE_UNKNOWN: 38 default: 39 return "?"; 40 } 41 42 // thread is stopped -- get the reason 43 switch (stoppedReason) { 44 case THREAD_STOPPED_DEBUGGER_CALL: 45 return "Call"; 46 case THREAD_STOPPED_EXCEPTION: 47 return "Exception"; 48 case THREAD_STOPPED_BREAKPOINT: 49 case THREAD_STOPPED_WATCHPOINT: 50 case THREAD_STOPPED_SINGLE_STEP: 51 case THREAD_STOPPED_DEBUGGED: 52 case THREAD_STOPPED_UNKNOWN: 53 default: 54 return "Debugged"; 55 } 56} 57 58 59/*static*/ const char* 60UiUtils::VariantToString(const BVariant& value, char* buffer, 61 size_t bufferSize) 62{ 63 if (!value.IsNumber()) 64 return value.ToString(); 65 66 switch (value.Type()) { 67 case B_FLOAT_TYPE: 68 case B_DOUBLE_TYPE: 69 snprintf(buffer, bufferSize, "%g", value.ToDouble()); 70 break; 71 case B_INT8_TYPE: 72 case B_UINT8_TYPE: 73 snprintf(buffer, bufferSize, "0x%02x", value.ToUInt8()); 74 break; 75 case B_INT16_TYPE: 76 case B_UINT16_TYPE: 77 snprintf(buffer, bufferSize, "0x%04x", value.ToUInt16()); 78 break; 79 case B_INT32_TYPE: 80 case B_UINT32_TYPE: 81 snprintf(buffer, bufferSize, "0x%08" B_PRIx32, 82 value.ToUInt32()); 83 break; 84 case B_INT64_TYPE: 85 case B_UINT64_TYPE: 86 default: 87 snprintf(buffer, bufferSize, "0x%016" B_PRIx64, 88 value.ToUInt64()); 89 break; 90 } 91 92 return buffer; 93} 94 95 96/*static*/ const char* 97UiUtils::FunctionNameForFrame(StackFrame* frame, char* buffer, 98 size_t bufferSize) 99{ 100 Image* image = frame->GetImage(); 101 FunctionInstance* function = frame->Function(); 102 if (image == NULL && function == NULL) { 103 snprintf(buffer, bufferSize, "?"); 104 return buffer; 105 } 106 107 BString name; 108 target_addr_t baseAddress; 109 if (function != NULL) { 110 name = function->PrettyName(); 111 baseAddress = function->Address(); 112 } else { 113 name = image->Name(); 114 baseAddress = image->Info().TextBase(); 115 } 116 117 snprintf(buffer, bufferSize, "%s + %#" B_PRIx64, 118 name.String(), frame->InstructionPointer() - baseAddress); 119 120 return buffer; 121} 122 123 124/*static*/ const char* 125UiUtils::ImageTypeToString(image_type type, char* buffer, size_t bufferSize) 126{ 127 switch (type) { 128 case B_APP_IMAGE: 129 snprintf(buffer, bufferSize, "Application"); 130 break; 131 case B_LIBRARY_IMAGE: 132 snprintf(buffer, bufferSize, "Library"); 133 break; 134 case B_ADD_ON_IMAGE: 135 snprintf(buffer, bufferSize, "Add-on"); 136 break; 137 case B_SYSTEM_IMAGE: 138 snprintf(buffer, bufferSize, "System"); 139 break; 140 default: 141 snprintf(buffer, bufferSize, "Unknown"); 142 break; 143 } 144 145 return buffer; 146} 147 148 149/*static*/ const char* 150UiUtils::ReportNameForTeam(::Team* team, char* buffer, size_t bufferSize) 151{ 152 BPath teamPath(team->Name()); 153 BDateTime currentTime; 154 currentTime.SetTime_t(time(NULL)); 155 snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02" 156 B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" 157 B_PRId32 ".report", teamPath.Leaf(), team->ID(), 158 currentTime.Date().Day(), currentTime.Date().Month(), 159 currentTime.Date().Year(), currentTime.Time().Hour(), 160 currentTime.Time().Minute(), currentTime.Time().Second()); 161 162 return buffer; 163 164} 165 166 167/*static*/ void 168UiUtils::PrintValueNodeGraph(BString& _output, ValueNodeChild* child, 169 int32 indentLevel, int32 maxDepth) 170{ 171 _output.Append('\t', indentLevel); 172 _output << child->Name(); 173 174 ValueNode* node = child->Node(); 175 if (node == NULL) { 176 _output << ": Unavailable\n"; 177 return; 178 } 179 180 if (node->GetType()->Kind() != TYPE_COMPOUND) { 181 _output << ": "; 182 status_t resolutionState = node->LocationAndValueResolutionState(); 183 if (resolutionState == VALUE_NODE_UNRESOLVED) 184 _output << "Unresolved"; 185 else if (resolutionState == B_OK) { 186 Value* value = node->GetValue(); 187 if (value != NULL) { 188 BString valueData; 189 value->ToString(valueData); 190 _output << valueData; 191 } else 192 _output << "Unavailable"; 193 } else 194 _output << strerror(resolutionState); 195 } 196 197 if (maxDepth == 0 || node->CountChildren() == 0) { 198 _output << "\n"; 199 return; 200 } 201 202 if (node->CountChildren() == 1 203 && node->GetType()->Kind() == TYPE_ADDRESS 204 && node->ChildAt(0)->GetType()->Kind() == TYPE_COMPOUND) { 205 // for the case of a pointer to a compound type, 206 // we want to hide the intervening compound node and print 207 // the children directly. 208 node = node->ChildAt(0)->Node(); 209 } 210 211 if (node != NULL) { 212 _output << " {\n"; 213 214 for (int32 i = 0; i < node->CountChildren(); i++) { 215 // don't dump compound nodes if our depth limit won't allow 216 // us to traverse into their children anyways, and the top 217 // level node contains no data of intereest. 218 if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND 219 || maxDepth > 1) { 220 PrintValueNodeGraph(_output, node->ChildAt(i), 221 indentLevel + 1, maxDepth - 1); 222 } 223 } 224 _output.Append('\t', indentLevel); 225 _output << "}\n"; 226 } else 227 _output << "\n"; 228 229 return; 230} 231 232 233/*static*/ void 234UiUtils::DumpMemory(BString& _output, int32 indentLevel, 235 TeamMemoryBlock* block, target_addr_t address, int32 itemSize, 236 int32 displayWidth, int32 count) 237{ 238 BString data; 239 240 int32 j; 241 _output.Append('\t', indentLevel); 242 for (int32 i = 0; i < count; i++) { 243 uint8* value; 244 245 if ((i % displayWidth) == 0) { 246 int32 displayed = min_c(displayWidth, (count-i)) * itemSize; 247 if (i != 0) { 248 _output.Append("\n"); 249 _output.Append('\t', indentLevel); 250 } 251 252 data.SetToFormat("[%#" B_PRIx64 "] ", address + i * itemSize); 253 _output += data; 254 char c; 255 for (j = 0; j < displayed; j++) { 256 if (!block->Contains(address + displayed)) 257 break; 258 c = *(block->Data() + address - block->BaseAddress() 259 + (i * itemSize) + j); 260 if (!isprint(c)) 261 c = '.'; 262 263 _output += c; 264 } 265 if (count > displayWidth) { 266 // make sure the spacing in the last line is correct 267 for (j = displayed; j < displayWidth * itemSize; j++) 268 _output += ' '; 269 } 270 _output.Append(" "); 271 } 272 273 value = block->Data() + address - block->BaseAddress() 274 + i * itemSize; 275 276 switch (itemSize) { 277 case 1: 278 data.SetToFormat(" %02" B_PRIx8, *(uint8*)value); 279 break; 280 case 2: 281 data.SetToFormat(" %04" B_PRIx16, *(uint16*)value); 282 break; 283 case 4: 284 data.SetToFormat(" %08" B_PRIx32, *(uint32*)value); 285 break; 286 case 8: 287 data.SetToFormat(" %016" B_PRIx64, *(uint64*)value); 288 break; 289 } 290 291 _output += data; 292 } 293 294 _output.Append("\n"); 295} 296