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