1 /* 2 * Copyright 2013-2015, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include "ExceptionStopConfigView.h" 6 7 #include <CheckBox.h> 8 #include <LayoutBuilder.h> 9 10 #include <AutoDeleter.h> 11 #include <AutoLocker.h> 12 13 #include "FunctionInstance.h" 14 #include "Image.h" 15 #include "ImageDebugInfo.h" 16 #include "MessageCodes.h" 17 #include "UserInterface.h" 18 #include "Team.h" 19 20 21 enum { 22 MSG_STOP_ON_THROWN_EXCEPTION_CHANGED = 'stec', 23 MSG_STOP_ON_CAUGHT_EXCEPTION_CHANGED = 'scec', 24 }; 25 26 27 ExceptionStopConfigView::ExceptionStopConfigView(::Team* team, 28 UserInterfaceListener* listener) 29 : 30 BGroupView(B_VERTICAL), 31 fTeam(team), 32 fListener(listener), 33 fExceptionThrown(NULL), 34 fExceptionCaught(NULL) 35 { 36 SetName("Exceptions"); 37 } 38 39 40 ExceptionStopConfigView::~ExceptionStopConfigView() 41 { 42 } 43 44 45 ExceptionStopConfigView* 46 ExceptionStopConfigView::Create(::Team* team, UserInterfaceListener* listener) 47 { 48 ExceptionStopConfigView* self = new ExceptionStopConfigView( 49 team, listener); 50 51 try { 52 self->_Init(); 53 } catch (...) { 54 delete self; 55 throw; 56 } 57 58 return self; 59 60 } 61 62 63 void 64 ExceptionStopConfigView::AttachedToWindow() 65 { 66 fExceptionThrown->SetTarget(this); 67 fExceptionCaught->SetTarget(this); 68 69 AutoLocker< ::Team> teamLocker(fTeam); 70 _UpdateExceptionState(); 71 72 BGroupView::AttachedToWindow(); 73 } 74 75 76 void 77 ExceptionStopConfigView::MessageReceived(BMessage* message) 78 { 79 switch (message->what) { 80 case MSG_STOP_ON_THROWN_EXCEPTION_CHANGED: 81 { 82 _UpdateThrownBreakpoints(fExceptionThrown->Value() 83 == B_CONTROL_ON); 84 break; 85 } 86 case MSG_STOP_ON_CAUGHT_EXCEPTION_CHANGED: 87 { 88 break; 89 } 90 default: 91 BGroupView::MessageReceived(message); 92 break; 93 } 94 95 } 96 97 98 void 99 ExceptionStopConfigView::_Init() 100 { 101 BLayoutBuilder::Group<>(this, B_VERTICAL) 102 .SetInsets(B_USE_DEFAULT_SPACING) 103 .AddGlue() 104 .Add(fExceptionThrown = new BCheckBox("exceptionThrown", 105 "Stop when an exception is thrown", 106 new BMessage(MSG_STOP_ON_THROWN_EXCEPTION_CHANGED))) 107 .Add(fExceptionCaught = new BCheckBox("exceptionCaught", 108 "Stop when an exception is caught", 109 new BMessage(MSG_STOP_ON_CAUGHT_EXCEPTION_CHANGED))) 110 .AddGlue(); 111 112 // TODO: enable once implemented 113 fExceptionCaught->SetEnabled(false); 114 } 115 116 117 void 118 ExceptionStopConfigView::_UpdateThrownBreakpoints(bool enable) 119 { 120 AutoLocker< ::Team> teamLocker(fTeam); 121 for (ImageList::ConstIterator it = fTeam->Images().GetIterator(); 122 it.HasNext();) { 123 Image* image = it.Next(); 124 125 ImageDebugInfo* info = image->GetImageDebugInfo(); 126 target_addr_t address; 127 if (_FindExceptionFunction(info, address) != B_OK) 128 continue; 129 130 if (enable) 131 fListener->SetBreakpointRequested(address, true, true); 132 else 133 fListener->ClearBreakpointRequested(address); 134 } 135 } 136 137 138 status_t 139 ExceptionStopConfigView::_FindExceptionFunction(ImageDebugInfo* info, 140 target_addr_t& _foundAddress) const 141 { 142 if (info != NULL) { 143 FunctionInstance* instance = info->FunctionByName( 144 "__cxa_allocate_exception"); 145 if (instance == NULL) 146 instance = info->FunctionByName("__throw(void)"); 147 148 if (instance != NULL) { 149 _foundAddress = instance->Address(); 150 return B_OK; 151 } 152 } 153 154 return B_NAME_NOT_FOUND; 155 } 156 157 158 void 159 ExceptionStopConfigView::_UpdateExceptionState() 160 { 161 // check if the exception breakpoints are already installed 162 for (ImageList::ConstIterator it = fTeam->Images().GetIterator(); 163 it.HasNext();) { 164 Image* image = it.Next(); 165 166 ImageDebugInfo* info = image->GetImageDebugInfo(); 167 target_addr_t address; 168 if (_FindExceptionFunction(info, address) != B_OK) 169 continue; 170 171 if (fTeam->BreakpointAtAddress(address) != NULL) { 172 fExceptionThrown->SetValue(B_CONTROL_ON); 173 break; 174 } 175 } 176 } 177