我正在编写一个小型调试器。当程序通过调用SymGetLineFromAddr64
打破调试器时,我试图找到文件和代码行。在主机进程被中断的同时,我调用GetThreadContext
来获取寄存器,StackWalk64
来获取当前堆栈,SymGetSymFromAddr64
来获取符号,所有这些都可以正常工作。然后我调用SymGetLineFromAddr64
,它失败了一系列奇怪的错误。输出的相关部分是:
Loaded 'D:\git\debugging\Debug\debugging.exe' at 10000000 with symbols.
(Later on, for the first auto-breakpoint that gets called when the program first starts running)
Breakpoint.
Thread context successful.
Stack walk successful.
SymGetLineFromAddr64(PC) error: 487/1e7
SymGetLineFromAddr64(Frame) error: 126/7e
SymGetLineFromAddr64(Stack) error: 126/7e
(I type 'go' and the program proceeds to an actual breakpoint, a __debugbreak() call in the program.)
Breakpoint.
Thread context successful.
Stack walk successful.
SymGetSymFromAddr64 failed. error: 126/7e
SymGetLineFromAddr64(PC) error: 126/7e
SymGetLineFromAddr64(Frame) error: 126/7e
SymGetLineFromAddr64(Stack) error: 126/7e
错误126 / 7e是ERROR_MOD_NOT_FOUND
,但我已经成功加载了调试符号,正如您从上面的输出中看到的那样。错误487 / 1e7是ERROR_INVALID_ADDRESS
,不知道这可能意味着什么以及为什么它只在程序计数器中显示当在内存窗口中提取指定的地址时给了我有效的内存,CC
断点正如您所期望的那样,在前一个地址中。
在有人问之前:是的,我确实看过这个问题:Why isn't SymGetSymFromAddr64 working? It returns error code 126从我的代码中我可以看到我已经有了一个SymInitialize,所以答案没有帮助。
完整代码列表:
#include <Windows.h>
#include <DbgHelp.h>
#include <Psapi.h>
#include <stdio.h>
#include <string>
#include <locale>
#include <codecvt>
HANDLE process_handle;
DWORD process_id;
HANDLE thread_handle;
DWORD thread_id;
const char* process_file = "D:\\git\\debugging\\Debug\\debugging.exe";
STACKFRAME64 stack;
typedef enum {
DBGFLAG_NONE = 0,
DBGFLAG_BROKEN = (1 << 0),
DBGFLAG_FIRSTBREAK = (1 << 1),
} dbgflags;
dbgflags debug_flags;
std::string GetFileNameFromHandle(HANDLE hFile);
char* EventIDToString(DWORD id)
{
switch (id)
{
case 3: return "CREATE_PROCESS_DEBUG_EVENT";
case 2: return "CREATE_THREAD_DEBUG_EVENT";
case 1: return "EXCEPTION_DEBUG_EVENT";
case 5: return "EXIT_PROCESS_DEBUG_EVENT";
case 4: return "EXIT_THREAD_DEBUG_EVENT";
case 6: return "LOAD_DLL_DEBUG_EVENT";
case 8: return "OUTPUT_DEBUG_STRING_EVENT";
case 9: return "RIP_EVENT";
case 7: return "UNLOAD_DLL_DEBUG_EVENT";
case 0: return "No event";
default: return "Unknown event";
}
}
DWORD ProcessEvent(DEBUG_EVENT* de)
{
switch (de->dwDebugEventCode)
{
default:
printf("Processing event code: %d (%s)\n", de->dwDebugEventCode, EventIDToString(de->dwDebugEventCode));
break;
case CREATE_PROCESS_DEBUG_EVENT:
{
DWORD options = SymGetOptions();
options |= SYMOPT_DEBUG;
::SymSetOptions(options);
std::string directory = process_file;
directory = directory.substr(0, directory.find_last_of('\\'));
BOOL r = SymInitialize(process_handle, directory.c_str(), false);
if (r)
printf("Initialized symbols\n");
else
{
printf("Symbol initialization failed\n");
break;
}
HANDLE hFile = CreateFile(process_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
DWORD size = GetFileSize(hFile, NULL);
CloseHandle(hFile);
DWORD64 dwBase = SymLoadModule64(process_handle, NULL, process_file, 0, (DWORD64)0x10000000, size);
IMAGEHLP_MODULE64 mi;
mi.SizeOfStruct = sizeof(mi);
r = SymGetModuleInfo64(process_handle, dwBase, &mi);
if (r && mi.SymType == SymPdb)
printf((std::string("Loaded '") + process_file + std::string("' at %x with symbols\n")).c_str(), 0x10000000);
else
printf((std::string("Loaded '") + process_file + std::string("' at %x without symbols\n")).c_str(), 0x10000000);
break;
}
case LOAD_DLL_DEBUG_EVENT:
{
std::string image = GetFileNameFromHandle(de->u.LoadDll.hFile);
DWORD64 dwBase = SymLoadModule64(process_handle, NULL, image.c_str(), 0, (DWORD64)de->u.LoadDll.lpBaseOfDll, 0);
IMAGEHLP_MODULE64 mi;
mi.SizeOfStruct = sizeof(mi);
BOOL r = SymGetModuleInfo64(process_handle, dwBase, &mi);
if (r && mi.SymType == SymPdb)
printf((std::string("Loaded '") + image + std::string("' at %x with symbols\n")).c_str(), de->u.LoadDll.lpBaseOfDll);
else
printf((std::string("Loaded '") + image + std::string("' at %x without symbols\n")).c_str(), de->u.LoadDll.lpBaseOfDll);
}
case EXCEPTION_DEBUG_EVENT:
{
DWORD code = de->u.Exception.ExceptionRecord.ExceptionCode;
switch (code)
{
case 0x80000003:
printf("Breakpoint.\n");
return DBG_CONTROL_BREAK;
break;
default:
printf("Exception code: %x\n", code);
return DBG_EXCEPTION_NOT_HANDLED;
}
break;
}
case OUTPUT_DEBUG_STRING_EVENT:
{
SIZE_T read;
char* buffer = new char[de->u.DebugString.nDebugStringLength*(de->u.DebugString.fUnicode + 1)];
ReadProcessMemory(process_handle, de->u.DebugString.lpDebugStringData, buffer, de->u.DebugString.nDebugStringLength, &read);
std::string debug;
if (de->u.DebugString.fUnicode)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
debug = converter.to_bytes((wchar_t*)buffer);
}
else
debug = buffer;
delete buffer;
printf("Debug: %s\n", debug.c_str());
break;
}
}
return DBG_CONTINUE;
}
void FindCode()
{
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)new char[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME];
memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME);
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol->MaxNameLength = MAX_SYM_NAME;
DWORD64 displacement64;
BOOL b = SymGetSymFromAddr64(process_handle, stack.AddrPC.Offset, &displacement64, symbol);
DWORD e = GetLastError();
if (!b)
printf("SymGetSymFromAddr64 failed. error: %d/%x\n", e, e);
DWORD displacement;
IMAGEHLP_LINE64 line = { 0 };
line.SizeOfStruct = sizeof(line);
BOOL r = SymGetLineFromAddr64(process_handle, stack.AddrPC.Offset, &displacement, &line);
e = GetLastError();
printf("SymGetLineFromAddr64(PC) error: %d/%x\n", e, e);
r = SymGetLineFromAddr64(process_handle, stack.AddrFrame.Offset, &displacement, &line);
e = GetLastError();
printf("SymGetLineFromAddr64(Frame) error: %d/%x\n", e, e);
r = SymGetLineFromAddr64(process_handle, stack.AddrStack.Offset, &displacement, &line);
e = GetLastError();
printf("SymGetLineFromAddr64(Stack) error: %d/%x\n", e, e);
/* const size_t file_length = 1000;
PSYMBOL_INFO si = (PSYMBOL_INFO)new char[sizeof(SYMBOL_INFO) + file_length];
memset(si, 0, sizeof(SYMBOL_INFO) + file_length);
si->SizeOfStruct = sizeof(SYMBOL_INFO);
si->MaxNameLen = file_length;
BOOL r = SymFromAddr(process_handle, stack.AddrPC.Offset, &displacement64, si);*/
delete symbol;
}
void main()
{
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
BOOL r = CreateProcess(NULL, (char*)process_file, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
process_handle = pi.hProcess;
process_id = pi.dwProcessId;
while (true)
{
if (debug_flags & DBGFLAG_BROKEN)
{
char input[100];
gets_s(input);
if (strcmp(input, "go") == 0)
{
printf("Continuing...\n");
ContinueDebugEvent(process_id, thread_id, DBG_CONTINUE);
debug_flags = (dbgflags)(debug_flags & ~DBGFLAG_BROKEN);
CloseHandle(thread_handle);
}
}
else
{
DEBUG_EVENT de = { 0 };
WaitForDebugEvent(&de, 0);
if (de.dwDebugEventCode)
{
DWORD control = ProcessEvent(&de);
thread_id = de.dwThreadId;
if (control == DBG_CONTROL_BREAK)
{
thread_handle = OpenThread(READ_CONTROL | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, de.dwThreadId);
debug_flags = (dbgflags)(debug_flags | DBGFLAG_BROKEN);
CONTEXT c = { 0 };
c.ContextFlags = CONTEXT_FULL;
BOOL b = GetThreadContext(thread_handle, &c);
if (b)
printf("Thread context successful.\n");
else
printf("Thread context failed.\n");
STACKFRAME64 sf = { 0 };
sf.AddrPC.Mode = sf.AddrFrame.Mode = sf.AddrStack.Mode = AddrModeFlat;
sf.AddrPC.Offset = c.Eip;
sf.AddrFrame.Offset = c.Ebp;
sf.AddrStack.Offset = c.Esp;
BOOL r = StackWalk64(IMAGE_FILE_MACHINE_I386, process_handle, thread_handle, &sf, &c,
NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL);
stack = sf;
if (r)
printf("Stack walk successful.\n");
else
printf("Stack walk failed.\n");
FindCode();
}
else
{
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, control);
if (!control)
process_handle = false;
}
}
}
}
}
std::string GetFileNameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH + 1];
HANDLE hFileMap;
std::string strFilename;
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
{
return FALSE;
}
// Create a file mapping object.
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
1,
NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName(GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
#define BUFSIZE 1000
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE - 1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = strlen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _strnicmp(pszFilename, szName,
uNameLen) == 0;
if (bFound)
{
strFilename = std::string(szDrive) + (pszFilename + uNameLen);
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}
return(strFilename);
}
答案 0 :(得分:0)
似乎CREATE_PROCESS_DEBUG_EVENT
执行SymLoadModule64
为时尚早,此时尚未加载模块。相反,如果程序断点被击中(即在FindCode
中),我会“及时”执行此操作,它似乎没有问题。