xref: /haiku/src/apps/debugger/user_interface/gui/team_window/StackTraceView.cpp (revision aed35104852941f0f6f3d1dcc5338b5f337d0a3c)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2011, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "StackTraceView.h"
9 
10 #include <stdio.h>
11 
12 #include <new>
13 
14 #include <ControlLook.h>
15 
16 #include "table/TableColumns.h"
17 
18 #include "FunctionInstance.h"
19 #include "GuiSettingsUtils.h"
20 #include "Image.h"
21 #include "StackTrace.h"
22 #include "TargetAddressTableColumn.h"
23 
24 
25 // #pragma mark - FramesTableModel
26 
27 
28 class StackTraceView::FramesTableModel : public TableModel {
29 public:
30 	FramesTableModel()
31 		:
32 		fStackTrace(NULL)
33 	{
34 	}
35 
36 	~FramesTableModel()
37 	{
38 		SetStackTrace(NULL);
39 	}
40 
41 	void SetStackTrace(StackTrace* stackTrace)
42 	{
43 		// unset old frames
44 		if (fStackTrace != NULL && fStackTrace->CountFrames())
45 			NotifyRowsRemoved(0, fStackTrace->CountFrames());
46 
47 		fStackTrace = stackTrace;
48 
49 		// set new frames
50 		if (fStackTrace != NULL && fStackTrace->CountFrames() > 0)
51 			NotifyRowsAdded(0, fStackTrace->CountFrames());
52 	}
53 
54 	virtual int32 CountColumns() const
55 	{
56 		return 3;
57 	}
58 
59 	virtual int32 CountRows() const
60 	{
61 		return fStackTrace != NULL ? fStackTrace->CountFrames() : 0;
62 	}
63 
64 	virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
65 	{
66 		StackFrame* frame
67 			= fStackTrace != NULL ? fStackTrace->FrameAt(rowIndex) : NULL;
68 		if (frame == NULL)
69 			return false;
70 
71 		switch (columnIndex) {
72 			case 0:
73 				value.SetTo(frame->FrameAddress());
74 				return true;
75 			case 1:
76 				value.SetTo(frame->InstructionPointer());
77 				return true;
78 			case 2:
79 			{
80 				Image* image = frame->GetImage();
81 				FunctionInstance* function = frame->Function();
82 				if (image == NULL && function == NULL) {
83 					value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
84 					return true;
85 				}
86 
87 				BString name;
88 				target_addr_t baseAddress;
89 				if (function != NULL) {
90 					name = function->PrettyName();
91 					baseAddress = function->Address();
92 				} else {
93 					name = image->Name();
94 					baseAddress = image->Info().TextBase();
95 				}
96 
97 				char offset[32];
98 				snprintf(offset, sizeof(offset), " + %#llx",
99 					frame->InstructionPointer() - baseAddress);
100 
101 				name << offset;
102 				value.SetTo(name.String());
103 
104 				return true;
105 			}
106 			default:
107 				return false;
108 		}
109 	}
110 
111 	StackFrame* FrameAt(int32 index) const
112 	{
113 		return fStackTrace != NULL ? fStackTrace->FrameAt(index) : NULL;
114 	}
115 
116 private:
117 	StackTrace*				fStackTrace;
118 };
119 
120 
121 // #pragma mark - StackTraceView
122 
123 
124 StackTraceView::StackTraceView(Listener* listener)
125 	:
126 	BGroupView(B_VERTICAL),
127 	fStackTrace(NULL),
128 	fFramesTable(NULL),
129 	fFramesTableModel(NULL),
130 	fListener(listener)
131 {
132 	SetName("Stack Trace");
133 }
134 
135 
136 StackTraceView::~StackTraceView()
137 {
138 	SetStackTrace(NULL);
139 	fFramesTable->SetTableModel(NULL);
140 	delete fFramesTableModel;
141 }
142 
143 
144 /*static*/ StackTraceView*
145 StackTraceView::Create(Listener* listener)
146 {
147 	StackTraceView* self = new StackTraceView(listener);
148 
149 	try {
150 		self->_Init();
151 	} catch (...) {
152 		delete self;
153 		throw;
154 	}
155 
156 	return self;
157 }
158 
159 
160 void
161 StackTraceView::UnsetListener()
162 {
163 	fListener = NULL;
164 }
165 
166 
167 void
168 StackTraceView::SetStackTrace(StackTrace* stackTrace)
169 {
170 	if (stackTrace == fStackTrace)
171 		return;
172 
173 	if (fStackTrace != NULL)
174 		fStackTrace->ReleaseReference();
175 
176 	fStackTrace = stackTrace;
177 
178 	if (fStackTrace != NULL)
179 		fStackTrace->AcquireReference();
180 
181 	fFramesTableModel->SetStackTrace(fStackTrace);
182 }
183 
184 
185 void
186 StackTraceView::SetStackFrame(StackFrame* stackFrame)
187 {
188 	if (fStackTrace != NULL && stackFrame != NULL) {
189 		for (int32 i = 0; StackFrame* other = fStackTrace->FrameAt(i); i++) {
190 			if (stackFrame == other) {
191 				fFramesTable->SelectRow(i, false);
192 				return;
193 			}
194 		}
195 	}
196 
197 	fFramesTable->DeselectAllRows();
198 }
199 
200 
201 void
202 StackTraceView::LoadSettings(const BMessage& settings)
203 {
204 	BMessage tableSettings;
205 	if (settings.FindMessage("framesTable", &tableSettings) == B_OK) {
206 		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
207 			fFramesTable);
208 	}
209 }
210 
211 
212 status_t
213 StackTraceView::SaveSettings(BMessage& settings)
214 {
215 	settings.MakeEmpty();
216 
217 	BMessage tableSettings;
218 	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
219 		fFramesTable);
220 	if (result == B_OK)
221 		result = settings.AddMessage("framesTable", &tableSettings);
222 
223 	return result;
224 }
225 
226 
227 void
228 StackTraceView::TableSelectionChanged(Table* table)
229 {
230 	if (fListener == NULL)
231 		return;
232 
233 	StackFrame* frame
234 		= fFramesTableModel->FrameAt(table->SelectionModel()->RowAt(0));
235 
236 	fListener->StackFrameSelectionChanged(frame);
237 }
238 
239 
240 void
241 StackTraceView::_Init()
242 {
243 	fFramesTable = new Table("stack trace", 0, B_FANCY_BORDER);
244 	AddChild(fFramesTable->ToView());
245 	fFramesTable->SetSortingEnabled(false);
246 
247 	float addressWidth = be_plain_font->StringWidth("0x00000000")
248 		+ be_control_look->DefaultLabelSpacing() * 2 + 5;
249 
250 	// columns
251 	fFramesTable->AddColumn(new TargetAddressTableColumn(0, "Frame",
252 		addressWidth, 40, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
253 	fFramesTable->AddColumn(new TargetAddressTableColumn(1, "IP", addressWidth,
254 		40, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
255 	fFramesTable->AddColumn(new StringTableColumn(2, "Function", 300, 100, 1000,
256 		B_TRUNCATE_END, B_ALIGN_LEFT));
257 
258 	fFramesTableModel = new FramesTableModel();
259 	fFramesTable->SetTableModel(fFramesTableModel);
260 
261 	fFramesTable->SetSelectionMode(B_SINGLE_SELECTION_LIST);
262 	fFramesTable->AddTableListener(this);
263 }
264 
265 
266 // #pragma mark - Listener
267 
268 
269 StackTraceView::Listener::~Listener()
270 {
271 }
272