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
21enum {
22	MSG_STOP_ON_THROWN_EXCEPTION_CHANGED	= 'stec',
23	MSG_STOP_ON_CAUGHT_EXCEPTION_CHANGED	= 'scec',
24};
25
26
27ExceptionStopConfigView::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
40ExceptionStopConfigView::~ExceptionStopConfigView()
41{
42}
43
44
45ExceptionStopConfigView*
46ExceptionStopConfigView::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
63void
64ExceptionStopConfigView::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
76void
77ExceptionStopConfigView::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
98void
99ExceptionStopConfigView::_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
117void
118ExceptionStopConfigView::_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
138status_t
139ExceptionStopConfigView::_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
158void
159ExceptionStopConfigView::_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