⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quincydebug.cpp

📁 一个完全使用MFC框架开发的C++编译器的代码。功能十分强大可以编译大型程序。
💻 CPP
字号:
// --------- QuincyDebug.cpp

#include "stdafx.h"
#include "Quincy.h"
#include "textview.h"
#include "debugger.h"
#include "WatchDialog.h"
#include "mainfrm.h"

Debugger* Debugger::pDebugger;

Debugger::Debugger()
{
	m_nDrive = _getdrive();
	m_pOldPath = _getcwd(0, MAX_PATH);
	std::string exe = theApp.GdbPath();
	exe += "gdb.exe";
//#ifdef CYGWIN_GDB
//	exe += "--args ";
//#endif
//	exe += " -q ";
	ConvertSlashes(exe);
	CString strexe = theApp.Enquote(exe.c_str()) + " ";
	gdb = new ConsoleApp(strexe, &Notify, &Collect);
	pDebugger = this;
	atprompt = false;
	watching = false;

	currentlineno = 0;
//	previouslineno = 0;
	infosent = false;
	ExamineWnd = 0;
	Expressions = 0;
	watchct = 0;
	watchiter = 0;
}

Debugger::~Debugger()
{

	_chdrive(m_nDrive);
	_chdir(m_pOldPath);
	delete m_pOldPath;
	delete gdb;
	pDebugger = 0;
}

void Debugger::LoadDebugger(std::string cmdline)
{
	try	{
		ConvertSlashes(cmdline);

		CString strCmdLine(cmdline.c_str());

		strRedirect.Empty();

		CString strRedirectedStdin;
		int index = strCmdLine.Find('<');
		if (index != -1 && index < strCmdLine.GetLength()-1)	{
			theApp.ParseFileSpec(strRedirectedStdin, strCmdLine, index);
			strRedirect = " < ";
			strRedirect += strRedirectedStdin;
		}
		CString strRedirectedStdout;
		index = strCmdLine.Find('>');
		if (index != -1 && index < strCmdLine.GetLength()-1)	{
			bool append = false;
			if (strCmdLine[index+1] == '>')	{
				index++;
				append = true;
			}
			theApp.ParseFileSpec(strRedirectedStdout, strCmdLine, index);
			strRedirect += append ? " >> " : " > ";
			strRedirect += strRedirectedStdout;
		}

		strCmdLine = theApp.Enquote(strCmdLine);

		gdb->Run(strCmdLine.GetBuffer(0));
//		gdb->Run(cmdline.c_str());
		theApp.ClearGdbConsole();
//		theApp.DisplayGdbText(strCmdLine.GetBuffer(0));
		theApp.DisplayGdbText("--- gdb started ---");
	}
	catch(...)	{
		AfxMessageBox("\nCannot execute GDB", MB_ICONSTOP);
	}
}

void Debugger::ConvertSlashes(std::string& str)
{
	for (int i = 0; i < str.size(); i++)
		if (str[i] == '\\')
			str[i] = '/';
}

void Debugger::SetTempBreakpoint(const Breakpoint& bp)
{
	char lineno[20];
	sprintf(lineno, "%d", bp.m_nLineNo);
	std::string cmd("tbreak ");
	cmd += theApp.GetFileName(bp.m_strFile);
	cmd += ':';
	cmd += lineno;
	SendCommand(const_cast<char*>(cmd.c_str()));
}

void Debugger::StartProgram()
{
	currentsrc = "";
	currentlineno = 0;
	atprompt = false;
	Breakpoint bp = theApp.SteptoBreakpoint();
	if (!bp.m_strFile.IsEmpty())
		SetTempBreakpoint(bp);
	if (theApp.IsConsoleApplication())
		PostCommand("set new-console");
	CString cmd("run");
	cmd += strRedirect;
	PostCommand(cmd.GetBuffer(0));
}

void Debugger::StepIntoProgram()
{
	UndoWatchDisplays();
	if (theApp.IsGUITarget())
		PostCommand("tbreak WinMain");
	else
		PostCommand("tbreak main");
	StartProgram();
}

void Debugger::SendCommand(char* cmd)
{
	if (atprompt)	{
		strncpy(lastcommand,cmd,99);
		gdb->WriteConsole(cmd);
		theApp.DisplayGdbText(cmd);
		atprompt = false;
	}
	else
		PostCommand(cmd);
}

void Debugger::PostCommand(const char* cmd)
{
	cmds.push(cmd);
}

void Debugger::Notify()
{
	ASSERT(pDebugger != 0);
	pDebugger->NotifyTermination();
}

void Debugger::NotifyTermination()
{
	if (atprompt)	{
		theApp.DisplayGdbText(" ");
		atprompt = false;
	}
	theApp.DisplayGdbText("--- gdb terminated ---");
	currentsrc = "";
	currentlineno = 0;
	theApp.InvalidateAllViews();
	UndoWatchDisplays();
	theApp.StopDebugger();  // this function in CQuincyApp destroys the debugger object
							// so don't do anything after this call except in the dtor
}

void Debugger::UndoWatchDisplays()
{
	for (watchiter = 0; watchiter < watchct; watchiter++)
		PostResponse("??");
	watchiter = 0;
}

// --- called from the console application thread while compiling is going on
void Debugger::Collect(DWORD bufct)
{
	ASSERT(pDebugger != 0);
	pDebugger->CollectGdbMessages(bufct);
}

inline bool Debugger::IsText(const char* buf, const char* txt) const
{
	return strnicmp(buf, txt, strlen(txt)-1) == 0;
}

void Debugger::SetWatchExpressions(CString* exp, int ct)
{
	Expressions = exp;
	watchct = ct;
	SendCommand("");
}

void Debugger::PostResponse(const char* res)
{
	CWatchDialog* watch = theApp.GetWatchDialog();
	if (watch)	{
		CListBox* lb = watch->GetWatchListbox();
		if (lb)	{
			std::string cmd(Expressions[watchiter]);
			int sel = lb->FindString(-1, cmd.c_str());
			if (sel != LB_ERR)	{
				lb->DeleteString(sel);
				cmd += res;
				lb->InsertString(sel, const_cast<char*>(cmd.c_str()));
			}
		}
	}
}

void Debugger::IterateWatches()
{
	if (watchct)	{
		watchiter++;
		if (watchiter == watchct)	{
			watchiter = 0;
			watching = false;
		}
	}
}

void Debugger::DisplayData(const char* cp)
{
	if (ExamineWnd != 0)	{
		// examine response
		if (::IsWindow(ExamineWnd->m_hWnd))
			ExamineWnd->SetWindowText(cp);
		ExamineWnd = 0;
	}
	else	{
		// watch response
		if (Expressions != 0)
			PostResponse(cp);
		IterateWatches();
	}
}

void Debugger::CollectGdbMessages(DWORD bufct)
{
	char *buf = new char[bufct+1];
	ASSERT(gdb != 0);
	if (gdb->ReadConsole(buf, bufct) != 0)	{
		if (!IsText(buf, "Note:"))	{
			if (*buf != ' ' || (steppingsrc.size() == 0 && strstr(buf, " at ")))
				theApp.DisplayGdbText(buf);

			if (IsText(buf, "Stack level"))	{
				// --- keep track of frame to support Step out of main function
				char *cp = strstr(buf, " at ");
				if (cp)	{
					cp += 4;
					frame = cp;
					if (mainframe.length() == 0)
						mainframe = frame;
				}
				// initiate collection of watches after info f data come in
				watching = Expressions != 0;
			}

			// ---- parse the message from gdb to see what to do with it besides display it
			else if (IsText(buf, "(gdb)"))	{
				// ---- this is the gdb prompt
				atprompt = true;
				if (strlen(buf) > 6)	// old gdb behavior
					// ---- error message from an Examine or Watch "print" command 
					//      appended to (gdb) prompt
					DisplayData("??");
				else
					// --- next display will be a command and will be appended 
					//     to the prompt on the display in the gdb console window
					theApp.AppendNextText();


				if (cmds.size() != 0)	{
					// ---- command(s) posted to be sent at the prompt
					SendCommand(const_cast<char*>(cmds.front().c_str()));
					cmds.pop();
				}
				else	{
					theApp.SetStepping();
					theApp.BringToTop();
					if (!watching)	{
						if (!infosent)	{
							// ---- send the info f command to get the current stack level
							SendCommand("info f");
							infosent = true;
						}
						else
							infosent = false;	// prevents (gdb) after info f output
												// is received from repeating info f
					}
					else if (watchiter < watchct)	{
						// get the data for the next watch in the watch window
						std::string cmd("print ");
						cmd += Expressions[watchiter].Left(Expressions[watchiter].GetLength()-4);
						ASSERT(gdb);
						gdb->WriteConsole(cmd.c_str());
						theApp.DisplayGdbText(const_cast<char*>(cmd.c_str()));
					}
				}
			}
			else if (IsText(buf, "No symbol"))
				DisplayData("??");
			else if (*buf == '$')	{
				char *cp = strstr(buf, " = ");
				if (cp)
					// --- response to "print" command from Examine or Watch
					DisplayData(cp+3);
			}
			else if (IsText(buf, "Program exited"))	{
				// ---- the program being debugged has exited on its own
				if (strstr(buf, " with code 03."))
					AfxMessageBox("assert failed", MB_ICONEXCLAMATION);
				SendCommand("q");
			}
			else if (IsText(buf, "The program is running"))	{
				// --- user must be stopping a running program
				atprompt = true;
				if (AfxMessageBox("Terminate running program?", MB_YESNO | MB_ICONQUESTION) == IDYES)	{
					SendCommand("y");
					frame = mainframe = "";
				}
				else
					SendCommand("n");
			}
			else if (strstr(buf, " in end ()") || strstr(buf, " in __mingw_CRTStartup ()"))
				// ---- this comes in after stepping out of main
				PostCommand("c");

			else if (IsText(buf, "0x"))	{
				if (buf[10] == ' ')	{
					if (isdigit(buf[11]))
						// --- one of those oddball step responses with the hex address 
						//     ahead of the line of code
						steppinglineno = atoi(buf+11);
					else	{
						goto testat;
					}
				}
			}
			
			else if (isdigit(*buf))
				// ---- single step. The numerical value is the line number
				steppinglineno = atoi(buf);

			else	{
testat:
				char *cp = strstr(buf, " at ");
				if (cp != 0)	{
					if (!IsText(cp+4, "0x") && !IsText(buf, "run till exit"))	{					
						// breakpoint or stepping into a new file
						cp += 4;
						std::string src;
						int lineno = 0;
						if (IsText(cp, "//") && *(cp+3) == '/')	{
							// non-dos file specification e.g. //c/foobar
							// convert to c:/foobar...
							cp++;
							*cp = *(cp+1);
							*(cp+1) = ':';
						}
						while (*cp && !(*cp == ':' && isdigit(*(cp+1))))	{
							// parse out file spec, ended with :<line#>
							src += (*cp == '/' ? '\\' : *cp);
							cp++;
						}
						if (*cp && *(cp+1))
							// parse out line number
							lineno = atoi(cp+1);
						if (lineno == steppinglineno && src == steppingsrc)
							// step or continue if this is a new file/lineno since last step or continue
							SendCommand(lastcommand);
						else	{
							// remember this step's file/lineno
							// --- check for valid source code file extension, step out if not
							int ndx = src.rfind('.');
							if (ndx != -1)	{
								std::string ext = src.substr(ndx, src.length() - ndx);
								if (ext != ".c" && ext != ".cpp" && ext != ".h")
									StepOut();
								else	{
									steppingsrc = src;
									steppinglineno = lineno;
								}
							}
							else
								StepOut();
						}
					}
				}
			}
		}
	}
	delete [] buf;
}

int Debugger::CurrentLineNo() const
{
	return currentlineno;
}
const CString* Debugger::CurrentSrcFile() const
{
	static CString str;
	str = currentsrc.c_str();
	return &str;
}

void Debugger::ShowPCCaret(bool bOnOff)
{
	if (currentlineno != 0)	{
		CTextView* pView = theApp.GetTextView(currentsrc.c_str());
		if (pView != 0)
			if (bOnOff)
				pView->DrawMargins();
			else
				pView->PadMargin();
	}
}

void Debugger::SelectSteppingSourceLine()
{
	ShowPCCaret(false);
	if (theApp.SelectFileAndLine(steppingsrc.c_str(), steppinglineno))	{
		currentsrc = steppingsrc;
		currentlineno = steppinglineno;
	}
	ShowPCCaret(true);
}

void Debugger::Stop()
{
	if (atprompt)
		SendCommand("q");
	else	{
		gdb->Stop();		
		atprompt = false;
		frame = mainframe = "";
	}
}

bool Debugger::StepTo(const CString& strFile, int nLineNo)
{
	if (atprompt)	{
		SetTempBreakpoint(Breakpoint(strFile, nLineNo));
		SendCommand("c");
		return true;
	}
	return false;
}

bool Debugger::ExecuteRunningProgram()
{
	if (atprompt)	{
		SendCommand("c");
		atprompt = false;
		return true;
	}
	return false;
}
// ------- the step command
bool Debugger::StepProgram()
{
	if (atprompt)	{
		SendCommand("step");
		atprompt = false;
		return true;
	}
	return false;
}
// ----- the step over command
bool Debugger::StepOver() 
{
	if (atprompt)	{
		SendCommand("next");
		atprompt = false;
		return true;
	}
	return false;
}

// ----- the step out command
void Debugger::StepOut() 
{
	if (atprompt)	{
		if (AtStackLevelZero())
			SendCommand("c");
	}
	else	{
		SendCommand("finish");
		atprompt = false;
		PostCommand("step");
	}
}

void Debugger::SetBreakpoint(Breakpoint& bp)
{
	char lineno[20];
	sprintf(lineno, "%d", bp.m_nLineNo);
	std::string cmd("break ");
	cmd += theApp.GetFileName(bp.m_strFile);
	cmd += ':';
	cmd += lineno;
	SendCommand(const_cast<char*>(cmd.c_str()));
}

void Debugger::ClearBreakpoint(Breakpoint& bp)
{
	char lineno[20];
	sprintf(lineno, "%d", bp.m_nLineNo);
	std::string cmd("clear ");
	cmd += theApp.GetFileName(bp.m_strFile);
	cmd += ':';
	cmd += lineno;
	if (!atprompt)
		PostCommand(const_cast<char*>(cmd.c_str()));
	else
		SendCommand(const_cast<char*>(cmd.c_str()));
}


void Debugger::GetVariableValue(const CString& strVarName, CWnd* wnd)
{
	ExamineWnd = wnd;
	std::string cmd("print ");
	cmd += strVarName;
	SendCommand(const_cast<char*>(cmd.c_str()));
}

void Debugger::SetVariableValue(const CString& strVarName, const CString& strVarValue)
{
	std::string cmd("set ");
	cmd += strVarName;
	cmd += "=";
	cmd += strVarValue;
	SendCommand(const_cast<char*>(cmd.c_str()));
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -