/* * Copyright 2012-2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "WatchPromptWindow.h" #include #include #include #include #include #include #include #include #include "AutoLocker.h" #include "AppMessageCodes.h" #include "Architecture.h" #include "CppLanguage.h" #include "IntegerValue.h" #include "MessageCodes.h" #include "SyntheticPrimitiveType.h" #include "UserInterface.h" #include "Watchpoint.h" WatchPromptWindow::WatchPromptWindow(Architecture* architecture, target_addr_t address, uint32 type, int32 length, UserInterfaceListener* listener) : BWindow(BRect(), "Edit Watchpoint", B_FLOATING_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), fInitialAddress(address), fInitialType(type), fInitialLength(length), fArchitecture(architecture), fRequestedAddress(0), fRequestedLength(0), fAddressInput(NULL), fLengthInput(NULL), fAddressExpressionInfo(NULL), fLengthExpressionInfo(NULL), fTypeField(NULL), fListener(listener), fLanguage(NULL) { fArchitecture->AcquireReference(); } WatchPromptWindow::~WatchPromptWindow() { fArchitecture->ReleaseReference(); if (fLanguage != NULL) fLanguage->ReleaseReference(); if (fAddressExpressionInfo != NULL) { fAddressExpressionInfo->RemoveListener(this); fAddressExpressionInfo->ReleaseReference(); } if (fLengthExpressionInfo != NULL) { fLengthExpressionInfo->RemoveListener(this); fLengthExpressionInfo->ReleaseReference(); } } WatchPromptWindow* WatchPromptWindow::Create(Architecture* architecture, target_addr_t address, uint32 type, int32 length, UserInterfaceListener* listener) { WatchPromptWindow* self = new WatchPromptWindow(architecture, address, type, length, listener); try { self->_Init(); } catch (...) { delete self; throw; } return self; } void WatchPromptWindow::_Init() { fLanguage = new CppLanguage(); BString text; text.SetToFormat("0x%" B_PRIx64, fInitialAddress); fAddressInput = new BTextControl("Address:", text, NULL); fAddressExpressionInfo = new ExpressionInfo(text); fAddressExpressionInfo->AddListener(this); text.SetToFormat("%" B_PRId32, fInitialLength); fLengthInput = new BTextControl("Length:", text, NULL); fLengthExpressionInfo = new ExpressionInfo(text); fLengthExpressionInfo->AddListener(this); int32 maxDebugRegisters = 0; int32 maxBytesPerRegister = 0; uint8 debugCapabilityFlags = 0; fArchitecture->GetWatchpointDebugCapabilities(maxDebugRegisters, maxBytesPerRegister, debugCapabilityFlags); BMenu* typeMenu = new BMenu("Watch type"); BMenuItem* watchTypeItem = new BMenuItem("Read", NULL); watchTypeItem->SetEnabled( (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ) != 0); typeMenu->AddItem(watchTypeItem); watchTypeItem = new BMenuItem("Write", NULL); watchTypeItem->SetEnabled( (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_WRITE) != 0); typeMenu->AddItem(watchTypeItem); watchTypeItem = new BMenuItem("Read/Write", NULL); watchTypeItem->SetEnabled( (debugCapabilityFlags & WATCHPOINT_CAPABILITY_FLAG_READ_WRITE) != 0); typeMenu->AddItem(watchTypeItem); fTypeField = new BMenuField("Type:", typeMenu); BLayoutItem* labelItem = fTypeField->CreateLabelLayoutItem(); labelItem->View()->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); BLayoutBuilder::Group<>(this, B_VERTICAL) .SetInsets(B_USE_DEFAULT_SPACING) .AddGroup(B_HORIZONTAL, 4.0f) .Add(fAddressInput) .End() .AddGroup(B_HORIZONTAL, 4.0f) .Add(fLengthInput) .Add(labelItem) .Add(fTypeField->CreateMenuBarLayoutItem()) .End() .AddGroup(B_HORIZONTAL, 4.0f) .AddGlue() .Add((fWatchButton = new BButton("Set", new BMessage(MSG_SET_WATCHPOINT)))) .Add((fCancelButton = new BButton("Cancel", new BMessage(B_QUIT_REQUESTED)))) .End(); fWatchButton->SetTarget(this); fCancelButton->SetTarget(this); fTypeField->Menu()->SetLabelFromMarked(true); fTypeField->Menu()->ItemAt(fInitialType)->SetMarked(true); } void WatchPromptWindow::Show() { CenterOnScreen(); BWindow::Show(); } void WatchPromptWindow::ExpressionEvaluated(ExpressionInfo* info, status_t result, ExpressionResult* value) { BMessage message(MSG_EXPRESSION_EVALUATED); message.AddInt32("result", result); message.AddPointer("info", info); BReference reference; if (value != NULL) { reference.SetTo(value); message.AddPointer("value", value); } if (PostMessage(&message) == B_OK) reference.Detach(); } void WatchPromptWindow::MessageReceived(BMessage* message) { switch (message->what) { case MSG_EXPRESSION_EVALUATED: { BString errorMessage; BReference reference; ExpressionResult* value = NULL; ExpressionInfo* info = NULL; if (message->FindPointer("info", reinterpret_cast(&info)) != B_OK) { break; } if (message->FindPointer("value", reinterpret_cast(&value)) == B_OK) { reference.SetTo(value, true); if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) { Value* primitive = value->PrimitiveValue(); if (dynamic_cast(primitive) != NULL) { BVariant resultVariant; primitive->ToVariant(resultVariant); if (info == fAddressExpressionInfo) { fRequestedAddress = resultVariant.ToUInt64(); break; } else fRequestedLength = resultVariant.ToInt32(); } else primitive->ToString(errorMessage); } else errorMessage.SetTo("Unsupported expression result."); } else { status_t result = message->FindInt32("result"); errorMessage.SetToFormat("Failed to evaluate expression: %s", strerror(result)); } if (fRequestedLength <= 0) errorMessage = "Watchpoint length must be at least 1 byte."; if (!errorMessage.IsEmpty()) { BAlert* alert = new(std::nothrow) BAlert("Edit Watchpoint", errorMessage.String(), "Close"); if (alert != NULL) alert->Go(); break; } fListener->ClearWatchpointRequested(fInitialAddress); fListener->SetWatchpointRequested(fRequestedAddress, fTypeField->Menu()->IndexOf(fTypeField->Menu()->FindMarked()), fRequestedLength, true); PostMessage(B_QUIT_REQUESTED); break; } case MSG_SET_WATCHPOINT: { fRequestedAddress = 0; fRequestedLength = 0; fAddressExpressionInfo->SetTo(fAddressInput->Text()); fListener->ExpressionEvaluationRequested(fLanguage, fAddressExpressionInfo); fLengthExpressionInfo->SetTo(fLengthInput->Text()); fListener->ExpressionEvaluationRequested(fLanguage, fLengthExpressionInfo); break; } default: BWindow::MessageReceived(message); break; } }