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