1. spencercw
  2. gb_emulator

Commits

spencercw  committed 7c73f24

Fix the stack trace to correctly handle fake calls followed by real returns.

  • Participants
  • Parent commits 64b1652
  • Branches debugger

Comments (0)

Files changed (3)

File gb_emulator/include/gb_emulator/gb_debugger.h

View file
 	uint16_t stackAddrMax;
 	uint16_t functionAddr;
 	uint16_t instructionAddr;
+	uint16_t returnAddr;
 };
 
 struct GB_EMULATOR_API GbRegisters

File gb_emulator/src/cdb_file.cpp

View file
 	{
 		return string();
 	}
-
-	// Find the associated function symbol, if available. The symbol address structure contains the
-	// name, but isn't necessarily a function, so this is just a check
-	map<string, Function>::const_iterator function = functions_.find(symAddr->second.name);
-	if (function == functions_.end())
+	else
 	{
-		return string();
+		return symAddr->second.name;
 	}
-
-	// Good match
-	return function->first;
 }

File gb_emulator/src/gb_debugger.cpp

View file
 	frame.stackAddrMax = 0xfffe;
 	frame.functionAddr = 0;
 	frame.instructionAddr = 0;
+	frame.returnAddr = 0;
 
 	stack_.push_back(frame);
 }
 		frame.stackAddrMax = gb_.cpu_.sp;
 		frame.functionAddr = 0x100;
 		frame.instructionAddr = 0x100;
+		frame.returnAddr = 0;
 		
 		stack_.push_back(frame);
 	}
 				frame.stackAddrMax = address;
 				frame.functionAddr = gb_.cpu_.pc;
 				frame.instructionAddr = gb_.cpu_.pc;
+				frame.returnAddr = 0;
 
 				stack_.push_back(frame);
 			}
 		}
 		break;
 
+	// PUSH
+	case 0xf5:
+	case 0xc5:
+	case 0xd5:
+	case 0xe5:
+		if (!stack_.empty())
+		{
+			GbStackFrame &frame = stack_.back();
+			frame.stackAddrMin -= 2;
+		}
+		break;
+
+	// POP
+	case 0xf1:
+	case 0xc1:
+	case 0xd1:
+	case 0xe1:
+		if (!stack_.empty())
+		{
+			GbStackFrame &frame = stack_.back();
+			frame.stackAddrMin += 2;
+		}
+		break;
+
+	// ADD SP, n
+	case 0xe8:
+		if (!stack_.empty())
+		{
+			GbStackFrame &frame = stack_.back();
+			int8_t n = gb_.mem_.read(gb_.cpu_.pc + 1);
+			frame.stackAddrMin += n;
+		}
+		break;
+
+	// INC SP
+	case 0x33:
+		if (!stack_.empty())
+		{
+			GbStackFrame &frame = stack_.back();
+			++frame.stackAddrMin;
+		}
+		break;
+
+	// DEC SP
+	case 0x3b:
+		if (!stack_.empty())
+		{
+			GbStackFrame &frame = stack_.back();
+			--frame.stackAddrMin;
+		}
+		break;
+
 	// CALL
 	case 0xcd:
 		handleCall(true);
 		frame.module = getModule();
 		frame.stackAddrMin = gb_.cpu_.sp - 2;
 		frame.stackAddrMax = gb_.cpu_.sp - 1;
+		frame.returnAddr = gb_.cpu_.pc;
 
 		if (interrupts & VBLANK_INTR)
 		{
 			frame.stackAddrMin = gb_.cpu_.sp - 2;
 			frame.stackAddrMax = gb_.cpu_.sp - 1;
 			frame.functionAddr = frame.instructionAddr = gb_.mem_.read16(gb_.cpu_.pc + 1);
+			frame.returnAddr = gb_.cpu_.pc + 3;
 
 			if (isRom)
 			{
 
 void GbDebugger::handleReturn(bool condition)
 {
-	if (condition && !stack_.empty())
+	if (condition)
 	{
-		stack_.pop_back();
+		if (stack_.empty())
+		{
+			return;
+		}
+
+		// Compare the return address of the current stack frame against the return addrress on the
+		// stack. If they differ either something has gone wrong, or the program has combined a fake
+		// call (i.e., manually pushing the return address onto the stack then jumping) with a real
+		// return. Lets hope its the latter and just ignore the return and adjust the stack range to
+		// account for the popped return address.
+		GbStackFrame &frame = stack_.back();
+		uint16_t returnAddr = gb_.mem_.read16(gb_.cpu_.sp);
+		if (frame.returnAddr == returnAddr)
+		{
+			stack_.pop_back();
+		}
 	}
 }