1 /* 2 * Copyright 2014-2015, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include "ExpressionEvaluationWindow.h" 6 7 #include <Button.h> 8 #include <LayoutBuilder.h> 9 #include <MenuField.h> 10 #include <String.h> 11 #include <TextControl.h> 12 13 #include "AutoLocker.h" 14 #include "CppLanguage.h" 15 #include "FunctionDebugInfo.h" 16 #include "FunctionInstance.h" 17 #include "MessageCodes.h" 18 #include "SourceLanguage.h" 19 #include "SpecificImageDebugInfo.h" 20 #include "StackFrame.h" 21 #include "StackTrace.h" 22 #include "Thread.h" 23 #include "UiUtils.h" 24 #include "UserInterface.h" 25 #include "ValueNodeManager.h" 26 27 28 enum { 29 MSG_THREAD_SELECTION_CHANGED = 'thsc', 30 MSG_FRAME_SELECTION_CHANGED = 'frsc' 31 }; 32 33 34 ExpressionEvaluationWindow::ExpressionEvaluationWindow(BHandler* closeTarget, 35 ::Team* team, UserInterfaceListener* listener) 36 : 37 BWindow(BRect(), "Evaluate Expression", B_TITLED_WINDOW, 38 B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), 39 fExpressionInput(NULL), 40 fThreadList(NULL), 41 fFrameList(NULL), 42 fVariablesView(NULL), 43 fCloseButton(NULL), 44 fEvaluateButton(NULL), 45 fCloseTarget(closeTarget), 46 fCurrentLanguage(NULL), 47 fFallbackLanguage(NULL), 48 fTeam(team), 49 fSelectedThread(NULL), 50 fSelectedFrame(NULL), 51 fListener(listener) 52 { 53 team->AddListener(this); 54 } 55 56 57 ExpressionEvaluationWindow::~ExpressionEvaluationWindow() 58 { 59 fTeam->RemoveListener(this); 60 61 if (fCurrentLanguage != NULL) 62 fCurrentLanguage->ReleaseReference(); 63 64 if (fFallbackLanguage != NULL) 65 fFallbackLanguage->ReleaseReference(); 66 67 if (fSelectedThread != NULL) 68 fSelectedThread->ReleaseReference(); 69 70 if (fSelectedFrame != NULL) 71 fSelectedFrame->ReleaseReference(); 72 } 73 74 75 ExpressionEvaluationWindow* 76 ExpressionEvaluationWindow::Create(BHandler* closeTarget, ::Team* team, 77 UserInterfaceListener* listener) 78 { 79 ExpressionEvaluationWindow* self = new ExpressionEvaluationWindow( 80 closeTarget, team, listener); 81 82 try { 83 self->_Init(); 84 } catch (...) { 85 delete self; 86 throw; 87 } 88 89 return self; 90 91 } 92 93 94 void 95 ExpressionEvaluationWindow::Show() 96 { 97 CenterOnScreen(); 98 BWindow::Show(); 99 } 100 101 102 bool 103 ExpressionEvaluationWindow::QuitRequested() 104 { 105 BMessenger messenger(fCloseTarget); 106 messenger.SendMessage(MSG_EXPRESSION_WINDOW_CLOSED); 107 108 return BWindow::QuitRequested(); 109 } 110 111 112 void 113 ExpressionEvaluationWindow::MessageReceived(BMessage* message) 114 { 115 switch (message->what) { 116 case MSG_THREAD_SELECTION_CHANGED: 117 { 118 int32 threadID; 119 if (message->FindInt32("thread", &threadID) != B_OK) 120 threadID = -1; 121 122 _HandleThreadSelectionChanged(threadID); 123 break; 124 } 125 126 case MSG_FRAME_SELECTION_CHANGED: 127 { 128 if (fSelectedThread == NULL) 129 break; 130 131 int32 frameIndex; 132 if (message->FindInt32("frame", &frameIndex) != B_OK) 133 frameIndex = -1; 134 135 _HandleFrameSelectionChanged(frameIndex); 136 break; 137 } 138 139 case MSG_EVALUATE_EXPRESSION: 140 { 141 BMessage message(MSG_ADD_NEW_EXPRESSION); 142 message.AddString("expression", fExpressionInput->Text()); 143 BMessenger(fVariablesView).SendMessage(&message); 144 break; 145 } 146 147 default: 148 BWindow::MessageReceived(message); 149 break; 150 } 151 152 } 153 154 155 void 156 ExpressionEvaluationWindow::ValueNodeValueRequested(CpuState* cpuState, 157 ValueNodeContainer* container, ValueNode* valueNode) 158 { 159 fListener->ValueNodeValueRequested(cpuState, container, valueNode); 160 } 161 162 163 void 164 ExpressionEvaluationWindow::ExpressionEvaluationRequested(ExpressionInfo* info, 165 StackFrame* frame, ::Thread* thread) 166 { 167 SourceLanguage* language = fCurrentLanguage; 168 if (fCurrentLanguage == NULL) 169 language = fFallbackLanguage; 170 fListener->ExpressionEvaluationRequested(language, info, frame, thread); 171 } 172 173 174 void 175 ExpressionEvaluationWindow::ValueNodeWriteRequested(ValueNode* node, 176 CpuState* state, Value* newValue) 177 { 178 } 179 180 181 void 182 ExpressionEvaluationWindow::_Init() 183 { 184 ValueNodeManager* nodeManager = new ValueNodeManager(false); 185 fExpressionInput = new BTextControl("Expression:", NULL, NULL); 186 BLayoutItem* labelItem = fExpressionInput->CreateLabelLayoutItem(); 187 BLayoutItem* inputItem = fExpressionInput->CreateTextViewLayoutItem(); 188 inputItem->SetExplicitMinSize(BSize(200.0, B_SIZE_UNSET)); 189 inputItem->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 190 labelItem->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 191 192 BLayoutBuilder::Group<>(this, B_VERTICAL) 193 .SetInsets(B_USE_DEFAULT_SPACING) 194 .AddGroup(B_HORIZONTAL, 4.0f) 195 .Add((fThreadList = new BMenuField("threadList", "Thread:", 196 new BMenu("Thread")))) 197 .Add((fFrameList = new BMenuField("frameList", "Frame:", 198 new BMenu("Frame")))) 199 .End() 200 .AddGroup(B_HORIZONTAL, 4.0f) 201 .Add(labelItem) 202 .Add(inputItem) 203 .End() 204 .Add(fVariablesView = VariablesView::Create(this, nodeManager)) 205 .AddGroup(B_HORIZONTAL, 4.0f) 206 .AddGlue() 207 .Add((fCloseButton = new BButton("Close", 208 new BMessage(B_QUIT_REQUESTED)))) 209 .Add((fEvaluateButton = new BButton("Evaluate", 210 new BMessage(MSG_EVALUATE_EXPRESSION)))) 211 .End(); 212 213 fCloseButton->SetTarget(this); 214 fEvaluateButton->SetTarget(this); 215 fExpressionInput->TextView()->MakeFocus(true); 216 217 fThreadList->Menu()->SetLabelFromMarked(true); 218 fFrameList->Menu()->SetLabelFromMarked(true); 219 220 fThreadList->Menu()->AddItem(new BMenuItem("<None>", 221 new BMessage(MSG_THREAD_SELECTION_CHANGED))); 222 fFrameList->Menu()->AddItem(new BMenuItem("<None>", 223 new BMessage(MSG_FRAME_SELECTION_CHANGED))); 224 225 _UpdateThreadList(); 226 227 fFallbackLanguage = new CppLanguage(); 228 } 229 230 231 void 232 ExpressionEvaluationWindow::_HandleThreadSelectionChanged(int32 threadID) 233 { 234 if (fSelectedThread != NULL) { 235 fSelectedThread->ReleaseReference(); 236 fSelectedThread = NULL; 237 } 238 239 AutoLocker< ::Team> teamLocker(fTeam); 240 fSelectedThread = fTeam->ThreadByID(threadID); 241 if (fSelectedThread != NULL) 242 fSelectedThread->AcquireReference(); 243 244 _UpdateFrameList(); 245 246 fVariablesView->SetStackFrame(fSelectedThread, fSelectedFrame); 247 } 248 249 250 void 251 ExpressionEvaluationWindow::_HandleFrameSelectionChanged(int32 index) 252 { 253 if (fSelectedFrame != NULL) { 254 fSelectedFrame->ReleaseReference(); 255 fSelectedFrame = NULL; 256 } 257 258 if (fCurrentLanguage != NULL) { 259 fCurrentLanguage->ReleaseReference(); 260 fCurrentLanguage = NULL; 261 } 262 263 AutoLocker< ::Team> teamLocker(fTeam); 264 StackTrace* stackTrace = fSelectedThread->GetStackTrace(); 265 if (stackTrace != NULL) { 266 fSelectedFrame = stackTrace->FrameAt(index); 267 if (fSelectedFrame != NULL) { 268 fSelectedFrame->AcquireReference(); 269 270 FunctionInstance* instance = fSelectedFrame->Function(); 271 if (instance != NULL) { 272 FunctionDebugInfo* functionInfo 273 = instance->GetFunctionDebugInfo(); 274 SpecificImageDebugInfo* imageInfo = 275 functionInfo->GetSpecificImageDebugInfo(); 276 277 if (imageInfo->GetSourceLanguage(functionInfo, 278 fCurrentLanguage) == B_OK) { 279 fCurrentLanguage->AcquireReference(); 280 } 281 } 282 } 283 } 284 285 fVariablesView->SetStackFrame(fSelectedThread, fSelectedFrame); 286 } 287 288 289 void 290 ExpressionEvaluationWindow::_UpdateThreadList() 291 { 292 AutoLocker< ::Team> teamLocker(fTeam); 293 294 BMenu* frameMenu = fFrameList->Menu(); 295 while (frameMenu->CountItems() > 1) 296 delete frameMenu->RemoveItem(1); 297 298 BMenu* threadMenu = fThreadList->Menu(); 299 while (threadMenu->CountItems() > 1) 300 delete threadMenu->RemoveItem(1); 301 302 const ThreadList& threads = fTeam->Threads(); 303 for (ThreadList::ConstIterator it = threads.GetIterator(); 304 ::Thread* thread = it.Next();) { 305 if (thread->State() != THREAD_STATE_STOPPED) 306 continue; 307 308 BString nameString; 309 nameString.SetToFormat("%" B_PRId32 ": %s", thread->ID(), 310 thread->Name()); 311 312 BMessage* message = new(std::nothrow) BMessage( 313 MSG_THREAD_SELECTION_CHANGED); 314 if (message == NULL) 315 return; 316 317 message->AddInt32("thread", thread->ID()); 318 319 BMenuItem* item = new(std::nothrow) BMenuItem(nameString, 320 message); 321 if (item == NULL) 322 return; 323 324 if (!threadMenu->AddItem(item)) 325 return; 326 327 if (fSelectedThread == NULL) { 328 item->SetMarked(true); 329 _HandleThreadSelectionChanged(thread->ID()); 330 } 331 } 332 333 if (fSelectedThread == NULL) 334 frameMenu->ItemAt(0L)->SetMarked(true); 335 336 } 337 338 339 void 340 ExpressionEvaluationWindow::_UpdateFrameList() 341 { 342 AutoLocker< ::Team> teamLocker(fTeam); 343 344 BMenu* frameMenu = fFrameList->Menu(); 345 while (frameMenu->CountItems() > 1) 346 delete frameMenu->RemoveItem(1); 347 348 frameMenu->ItemAt(0L)->SetMarked(true); 349 350 if (fSelectedThread == NULL) 351 return; 352 353 StackTrace* stackTrace = fSelectedThread->GetStackTrace(); 354 if (stackTrace == NULL) 355 return; 356 357 char buffer[128]; 358 for (int32 i = 0; i < stackTrace->CountFrames(); i++) { 359 StackFrame* frame = stackTrace->FrameAt(i); 360 UiUtils::FunctionNameForFrame(frame, buffer, sizeof(buffer)); 361 362 BMessage* message = new(std::nothrow) BMessage( 363 MSG_FRAME_SELECTION_CHANGED); 364 if (message == NULL) 365 return; 366 367 message->AddInt32("frame", i); 368 369 BMenuItem* item = new(std::nothrow) BMenuItem(buffer, 370 message); 371 if (item == NULL) 372 return; 373 374 if (!frameMenu->AddItem(item)) 375 return; 376 377 if (fSelectedFrame == NULL) { 378 item->SetMarked(true); 379 _HandleFrameSelectionChanged(i); 380 } 381 } 382 } 383