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