1 /* 2 * Copyright 2012-2014, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include "WatchPromptWindow.h" 6 7 #include <Alert.h> 8 #include <Button.h> 9 #include <LayoutBuilder.h> 10 #include <Menu.h> 11 #include <MenuField.h> 12 #include <MenuItem.h> 13 #include <String.h> 14 #include <TextControl.h> 15 16 #include "AutoLocker.h" 17 18 #include "Architecture.h" 19 #include "CppLanguage.h" 20 #include "IntegerValue.h" 21 #include "MessageCodes.h" 22 #include "SyntheticPrimitiveType.h" 23 #include "UserInterface.h" 24 #include "Watchpoint.h" 25 26 27 WatchPromptWindow::WatchPromptWindow(Architecture* architecture, 28 target_addr_t address, uint32 type, int32 length, 29 UserInterfaceListener* listener) 30 : 31 BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW, 32 B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), 33 fInitialAddress(address), 34 fInitialType(type), 35 fInitialLength(length), 36 fArchitecture(architecture), 37 fRequestedAddress(0), 38 fRequestedLength(0), 39 fAddressInput(NULL), 40 fLengthInput(NULL), 41 fAddressExpressionInfo(NULL), 42 fLengthExpressionInfo(NULL), 43 fTypeField(NULL), 44 fListener(listener), 45 fLanguage(NULL) 46 { 47 fArchitecture->AcquireReference(); 48 } 49 50 51 WatchPromptWindow::~WatchPromptWindow() 52 { 53 fArchitecture->ReleaseReference(); 54 55 if (fLanguage != NULL) 56 fLanguage->ReleaseReference(); 57 58 if (fAddressExpressionInfo != NULL) { 59 fAddressExpressionInfo->RemoveListener(this); 60 fAddressExpressionInfo->ReleaseReference(); 61 } 62 63 if (fLengthExpressionInfo != NULL) { 64 fLengthExpressionInfo->RemoveListener(this); 65 fLengthExpressionInfo->ReleaseReference(); 66 } 67 } 68 69 70 WatchPromptWindow* 71 WatchPromptWindow::Create(Architecture* architecture, target_addr_t address, 72 uint32 type, int32 length, UserInterfaceListener* listener) 73 { 74 WatchPromptWindow* self = new WatchPromptWindow(architecture, address, 75 type, length, listener); 76 77 try { 78 self->_Init(); 79 } catch (...) { 80 delete self; 81 throw; 82 } 83 84 return self; 85 86 } 87 88 89 void 90 WatchPromptWindow::_Init() 91 { 92 fLanguage = new CppLanguage(); 93 94 BString text; 95 text.SetToFormat("0x%" B_PRIx64, fInitialAddress); 96 fAddressInput = new BTextControl("Address:", text, NULL); 97 fAddressExpressionInfo = new ExpressionInfo(text); 98 fAddressExpressionInfo->AddListener(this); 99 100 text.SetToFormat("%" B_PRId32, fInitialLength); 101 fLengthInput = new BTextControl("Length:", text, NULL); 102 fLengthExpressionInfo = new ExpressionInfo(text); 103 fLengthExpressionInfo->AddListener(this); 104 105 int32 maxDebugRegisters = 0; 106 int32 maxBytesPerRegister = 0; 107 uint8 debugCapabilityFlags = 0; 108 fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters, 109 maxBytesPerRegister, debugCapabilityFlags); 110 111 BMenu* typeMenu = new BMenu("Watch type"); 112 113 BMenuItem* watchTypeItem = new BMenuItem("Read", NULL); 114 watchTypeItem->SetEnabled( 115 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0); 116 typeMenu->AddItem(watchTypeItem); 117 118 watchTypeItem = new BMenuItem("Write", NULL); 119 watchTypeItem->SetEnabled( 120 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0); 121 typeMenu->AddItem(watchTypeItem); 122 123 watchTypeItem = new BMenuItem("Read/Write", NULL); 124 watchTypeItem->SetEnabled( 125 (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0); 126 typeMenu->AddItem(watchTypeItem); 127 128 fTypeField = new BMenuField("Type:", typeMenu); 129 BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem(); 130 labelItem->View()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 131 BLayoutBuilder::Group<>(this, B_VERTICAL) 132 .SetInsets(B_USE_DEFAULT_SPACING) 133 .AddGroup(B_HORIZONTAL, 4.0f) 134 .Add(fAddressInput) 135 .End() 136 .AddGroup(B_HORIZONTAL, 4.0f) 137 .Add(fLengthInput) 138 .Add(labelItem) 139 .Add(fTypeField->CreateMenuBarLayoutItem()) 140 .End() 141 .AddGroup(B_HORIZONTAL, 4.0f) 142 .AddGlue() 143 .Add((fWatchButton = new BButton("Set", 144 new BMessage(MSG_SET_WATCHPOINT)))) 145 .Add((fCancelButton = new BButton("Cancel", 146 new BMessage(B_QUIT_REQUESTED)))) 147 .End(); 148 149 fWatchButton->SetTarget(this); 150 fCancelButton->SetTarget(this); 151 152 fTypeField->Menu()->SetLabelFromMarked(true); 153 fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true); 154 } 155 156 157 void 158 WatchPromptWindow::Show() 159 { 160 CenterOnScreen(); 161 BWindow::Show(); 162 } 163 164 165 void 166 WatchPromptWindow::ExpressionEvaluated(ExpressionInfo* info, status_t result, 167 ExpressionResult* value) 168 { 169 BMessage message(MSG_EXPRESSION_EVALUATED); 170 message.AddInt32("result", result); 171 message.AddPointer("info", info); 172 BReference<ExpressionResult> reference; 173 if (value != NULL) { 174 reference.SetTo(value); 175 message.AddPointer("value", value); 176 } 177 178 if (PostMessage(&message) == B_OK) 179 reference.Detach(); 180 } 181 182 183 void 184 WatchPromptWindow::MessageReceived(BMessage* message) 185 { 186 switch (message->what) { 187 case MSG_EXPRESSION_EVALUATED: 188 { 189 BString errorMessage; 190 BReference<ExpressionResult> reference; 191 ExpressionResult* value = NULL; 192 ExpressionInfo* info = NULL; 193 if (message->FindPointer("info", 194 reinterpret_cast<void**>(&info)) != B_OK) { 195 break; 196 } 197 198 if (message->FindPointer("value", 199 reinterpret_cast<void**>(&value)) == B_OK) { 200 reference.SetTo(value, true); 201 if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) { 202 Value* primitive = value->PrimitiveValue(); 203 if (dynamic_cast<IntegerValue*>(primitive) != NULL) { 204 BVariant resultVariant; 205 primitive->ToVariant(resultVariant); 206 if (info == fAddressExpressionInfo) { 207 fRequestedAddress = resultVariant.ToUInt64(); 208 break; 209 } else 210 fRequestedLength = resultVariant.ToInt32(); 211 } 212 else 213 primitive->ToString(errorMessage); 214 } else 215 errorMessage.SetTo("Unsupported expression result."); 216 } else { 217 status_t result = message->FindInt32("result"); 218 errorMessage.SetToFormat("Failed to evaluate expression: %s", 219 strerror(result)); 220 } 221 222 if (fRequestedLength <= 0) 223 errorMessage = "Watchpoint length must be at least 1 byte."; 224 225 if (!errorMessage.IsEmpty()) { 226 BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint", 227 errorMessage.String(), "Close"); 228 if (alert != NULL) 229 alert->Go(); 230 break; 231 } 232 233 fListener->ClearWatchpointRequested(fInitialAddress); 234 fListener->SetWatchpointRequested(fRequestedAddress, 235 fTypeField->Menu()->IndexOf(fTypeField->Menu()->FindMarked()), 236 fRequestedLength, true); 237 238 PostMessage(B_QUIT_REQUESTED); 239 break; 240 } 241 242 case MSG_SET_WATCHPOINT: 243 { 244 fRequestedAddress = 0; 245 fRequestedLength = 0; 246 247 fAddressExpressionInfo->SetTo(fAddressInput->Text()); 248 fListener->ExpressionEvaluationRequested(fLanguage, 249 fAddressExpressionInfo); 250 251 fLengthExpressionInfo->SetTo(fLengthInput->Text()); 252 fListener->ExpressionEvaluationRequested(fLanguage, 253 fLengthExpressionInfo); 254 break; 255 } 256 257 default: 258 BWindow::MessageReceived(message); 259 break; 260 } 261 262 } 263