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