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