| 
									
										
										
										
											2015-01-04 09:36:57 -08:00
										 |  |  | // Copyright 2014 Citra Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-11 00:23:00 -04:00
										 |  |  | #include "citra_qt/debugger/callstack.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-21 00:21:23 +09:00
										 |  |  | #include <QStandardItemModel>
 | 
					
						
							| 
									
										
										
										
											2015-08-11 22:32:39 +01:00
										 |  |  | #include "common/common_types.h"
 | 
					
						
							|  |  |  | #include "common/symbols.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-11 00:23:00 -04:00
										 |  |  | #include "core/arm/arm_interface.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  | #include "core/arm/disassembler/arm_disasm.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | #include "core/core.h"
 | 
					
						
							|  |  |  | #include "core/memory.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | CallstackWidget::CallstackWidget(QWidget* parent) : QDockWidget(parent) { | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |     ui.setupUi(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     callstack_model = new QStandardItemModel(this); | 
					
						
							|  |  |  |     callstack_model->setColumnCount(4); | 
					
						
							| 
									
										
										
										
											2014-12-31 23:03:15 +01:00
										 |  |  |     callstack_model->setHeaderData(0, Qt::Horizontal, "Stack Pointer"); | 
					
						
							|  |  |  |     callstack_model->setHeaderData(2, Qt::Horizontal, "Return Address"); | 
					
						
							|  |  |  |     callstack_model->setHeaderData(1, Qt::Horizontal, "Call Address"); | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |     callstack_model->setHeaderData(3, Qt::Horizontal, "Function"); | 
					
						
							|  |  |  |     ui.treeView->setModel(callstack_model); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | void CallstackWidget::OnDebugModeEntered() { | 
					
						
							| 
									
										
										
										
											2015-12-29 18:03:08 -05:00
										 |  |  |     // Stack pointer
 | 
					
						
							|  |  |  |     const u32 sp = Core::g_app_core->GetReg(13); | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-10 22:39:00 -08:00
										 |  |  |     Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |     int counter = 0; | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |     for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { | 
					
						
							| 
									
										
										
										
											2016-04-16 09:48:46 +01:00
										 |  |  |         if (!Memory::IsValidVirtualAddress(addr)) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-29 18:03:08 -05:00
										 |  |  |         const u32 ret_addr = Memory::Read32(addr); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         const u32 call_addr = ret_addr - 4; // get call address???
 | 
					
						
							| 
									
										
										
										
											2015-05-25 20:34:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 09:48:46 +01:00
										 |  |  |         if (!Memory::IsValidVirtualAddress(call_addr)) | 
					
						
							| 
									
										
										
										
											2015-01-07 21:39:40 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* TODO (mattvail) clean me, move to debugger interface */ | 
					
						
							|  |  |  |         u32 insn = Memory::Read32(call_addr); | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |         if (ARM_Disasm::Decode(insn) == OP_BL) { | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |             std::string name; | 
					
						
							|  |  |  |             // ripped from disasm
 | 
					
						
							| 
									
										
										
										
											2015-08-11 22:32:39 +01:00
										 |  |  |             u8 cond = (insn >> 28) & 0xf; | 
					
						
							|  |  |  |             u32 i_offset = insn & 0xffffff; | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |             // Sign-extend the 24-bit offset
 | 
					
						
							|  |  |  |             if ((i_offset >> 23) & 1) | 
					
						
							|  |  |  |                 i_offset |= 0xff000000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Pre-compute the left-shift and the prefetch offset
 | 
					
						
							|  |  |  |             i_offset <<= 2; | 
					
						
							|  |  |  |             i_offset += 8; | 
					
						
							| 
									
										
										
										
											2015-12-29 18:03:08 -05:00
										 |  |  |             const u32 func_addr = call_addr + i_offset; | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             callstack_model->setItem( | 
					
						
							|  |  |  |                 counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); | 
					
						
							|  |  |  |             callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg( | 
					
						
							|  |  |  |                                                      ret_addr, 8, 16, QLatin1Char('0')))); | 
					
						
							|  |  |  |             callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg( | 
					
						
							|  |  |  |                                                      call_addr, 8, 16, QLatin1Char('0')))); | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  |             name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  |             callstack_model->setItem( | 
					
						
							|  |  |  |                 counter, 3, new QStandardItem( | 
					
						
							|  |  |  |                                 QString("%1_%2") | 
					
						
							|  |  |  |                                     .arg(QString::fromStdString(name)) | 
					
						
							|  |  |  |                                     .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); | 
					
						
							| 
									
										
										
										
											2014-04-18 18:30:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |             counter++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-11-19 08:49:13 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-07 12:14:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 18:01:46 -07:00
										 |  |  | void CallstackWidget::OnDebugModeLeft() {} | 
					
						
							| 
									
										
										
										
											2015-01-10 22:39:00 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-18 09:38:01 +09:00
										 |  |  | void CallstackWidget::Clear() { | 
					
						
							| 
									
										
										
										
											2015-01-10 22:39:00 -08:00
										 |  |  |     for (int row = 0; row < callstack_model->rowCount(); row++) { | 
					
						
							|  |  |  |         for (int column = 0; column < callstack_model->columnCount(); column++) { | 
					
						
							|  |  |  |             callstack_model->setItem(row, column, new QStandardItem()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |