1
0
Fork 0

DBG: better heuristics for detecting the debuggee did not terminate after 10 seconds

This commit is contained in:
Duncan Ogilvie 2019-07-07 18:30:58 +02:00
parent 8a07bd2d7e
commit 7212e853fb
5 changed files with 77 additions and 47 deletions

View File

@ -161,6 +161,7 @@ bool cbDebugStop(int argc, char* argv[])
//history
HistoryClear();
DWORD BeginTick = GetTickCount();
bool shownWarning = false;
while(true)
{
@ -174,15 +175,24 @@ bool cbDebugStop(int argc, char* argv[])
{
unlock(WAITID_RUN);
DWORD CurrentTick = GetTickCount();
if(CurrentTick - BeginTick > 10000)
DWORD TimeElapsed = CurrentTick - BeginTick;
if(TimeElapsed >= 10000)
{
dputs(QT_TRANSLATE_NOOP("DBG", "The debuggee does not stop after 10 seconds. The debugger state may be corrupted."));
DbSave(DbLoadSaveType::All);
TerminateThread(hDebugLoopThreadCopy, 1); // TODO: this will lose state and cause possible corruption if a critical section is still owned
CloseHandle(hDebugLoopThreadCopy);
return false;
if(!shownWarning)
{
shownWarning = true;
dputs(QT_TRANSLATE_NOOP("DBG", "Finalizing the debugger thread took more than 10 seconds. This can happen if you are loading large symbol files or saving a large database."));
}
if(IsFileBeingDebugged() || TimeElapsed >= 100000)
{
dputs(QT_TRANSLATE_NOOP("DBG", "The debuggee did not stop after 10 seconds of requesting termination. The debugger state may be corrupted. It is recommended to restart x64dbg."));
DbSave(DbLoadSaveType::All);
TerminateThread(hDebugLoopThreadCopy, 1); // TODO: this will lose state and cause possible corruption if a critical section is still owned
CloseHandle(hDebugLoopThreadCopy);
return false;
}
}
if(CurrentTick - BeginTick >= 300)
if(TimeElapsed >= 300)
TerminateProcess(fdProcessInfo->hProcess, -1);
}
break;

View File

@ -444,7 +444,7 @@ std::string PDBDiaFile::getSymbolUndecoratedNameString(IDiaSymbol* sym)
return result;
}
bool PDBDiaFile::enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files)
bool PDBDiaFile::enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files, const std::atomic<bool> & cancelled)
{
HRESULT hr;
DWORD lineNumber = 0;
@ -465,49 +465,69 @@ bool PDBDiaFile::enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<D
return true;
lines.reserve(lines.size() + lineCount);
std::vector<IDiaLineNumber*> lineNumbers;
lineNumbers.resize(lineCount);
ULONG fetched = 0;
hr = lineNumbersEnum->Next(lineCount, lineNumbers.data(), &fetched);
for(ULONG n = 0; n < fetched; n++)
const ULONG bucket = 10000;
ULONG steps = lineCount / bucket + (lineCount % bucket != 0);
for(ULONG step = 0; step < steps; step++)
{
CComPtr<IDiaLineNumber> lineNumberInfo;
lineNumberInfo.Attach(lineNumbers[n]);
ULONG begin = step * bucket;
ULONG end = min(lineCount, (step + 1) * bucket);
DWORD sourceFileId = 0;
hr = lineNumberInfo->get_sourceFileId(&sourceFileId);
if(!SUCCEEDED(hr))
continue;
if(cancelled)
return false;
if(!files.count(sourceFileId))
std::vector<IDiaLineNumber*> lineNumbers;
ULONG lineCountStep = end - begin;
lineNumbers.resize(lineCountStep);
ULONG fetched = 0;
hr = lineNumbersEnum->Next((ULONG)lineNumbers.size(), lineNumbers.data(), &fetched);
for(ULONG n = 0; n < fetched; n++)
{
CComPtr<IDiaSourceFile> sourceFile;
hr = lineNumberInfo->get_sourceFile(&sourceFile);
if(cancelled)
{
for(ULONG m = n; m < fetched; m++)
lineNumbers[m]->Release();
return false;
}
CComPtr<IDiaLineNumber> lineNumberInfo;
lineNumberInfo.Attach(lineNumbers[n]);
DWORD sourceFileId = 0;
hr = lineNumberInfo->get_sourceFileId(&sourceFileId);
if(!SUCCEEDED(hr))
continue;
BSTR fileName = nullptr;
hr = sourceFile->get_fileName(&fileName);
if(!files.count(sourceFileId))
{
CComPtr<IDiaSourceFile> sourceFile;
hr = lineNumberInfo->get_sourceFile(&sourceFile);
if(!SUCCEEDED(hr))
continue;
BSTR fileName = nullptr;
hr = sourceFile->get_fileName(&fileName);
if(!SUCCEEDED(hr))
continue;
files.insert({ sourceFileId, StringUtils::Utf16ToUtf8(fileName) });
SysFreeString(fileName);
}
DiaLineInfo_t lineInfo;
lineInfo.sourceFileId = sourceFileId;
hr = lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
if(!SUCCEEDED(hr))
continue;
files.insert({ sourceFileId, StringUtils::Utf16ToUtf8(fileName) });
SysFreeString(fileName);
hr = lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
if(!SUCCEEDED(hr))
continue;
lines.push_back(lineInfo);
}
DiaLineInfo_t lineInfo;
lineInfo.sourceFileId = sourceFileId;
hr = lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
if(!SUCCEEDED(hr))
continue;
hr = lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
if(!SUCCEEDED(hr))
continue;
lines.push_back(lineInfo);
}
return true;

View File

@ -8,6 +8,7 @@
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <atomic>
struct IDiaDataSource;
struct IDiaSession;
@ -50,7 +51,7 @@ public:
bool close();
bool enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files);
bool enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files, const std::atomic<bool> & cancelled);
bool enumerateLexicalHierarchy(const Query_t & query);

View File

@ -99,10 +99,6 @@ bool SymbolSourceDIA::cancelLoading()
return true;
}
void SymbolSourceDIA::loadPDBAsync()
{
}
template<size_t Count>
static bool startsWith(const char* str, const char(&prefix)[Count])
{
@ -257,12 +253,12 @@ bool SymbolSourceDIA::loadSourceLinesAsync()
std::vector<DiaLineInfo_t> lines;
std::map<DWORD, String> files;
if(!pdb.enumerateLineNumbers(0, uint32_t(_imageSize), lines, files))
if(!pdb.enumerateLineNumbers(0, uint32_t(_imageSize), lines, files, _requiresShutdown))
return false;
if(files.size() == 1)
{
GuiSymbolLogAdd(StringUtils::sprintf("[%p, %s] Since there is only one file, attempting line overflow detection..\n", _imageBase, _modname.c_str()).c_str());
GuiSymbolLogAdd(StringUtils::sprintf("[%p, %s] Since there is only one file, attempting line overflow detection (%ums)..\n", _imageBase, _modname.c_str(), GetTickCount() - lineLoadStart).c_str());
// This is a super hack to adjust for the (undocumented) limit of 16777215 lines (unsigned 24 bits maximum).
// It is unclear at this point if yasm/coff/link/pdb is causing this issue.
@ -271,6 +267,9 @@ bool SymbolSourceDIA::loadSourceLinesAsync()
uint32_t maxLine = 0, maxRva = 0, lineOverflows = 0;
for(auto & line : lines)
{
if(_requiresShutdown)
return false;
uint32_t overflowValue = 0x1000000 * (lineOverflows + 1) - 1; //0xffffff, 0x1ffffff, 0x2ffffff, etc
if((line.lineNumber & 0xfffff0) == 0 && (maxLine & 0xfffffff0) == (overflowValue & 0xfffffff0)) // allow 16 lines of play, perhaps there is a label/comment on line 0xffffff+1
{
@ -294,6 +293,7 @@ bool SymbolSourceDIA::loadSourceLinesAsync()
_linesData.reserve(lines.size());
_sourceFiles.reserve(files.size());
for(const auto & line : lines)
{
if(_requiresShutdown)

View File

@ -147,7 +147,6 @@ public:
bool loadPDB(const std::string & path, const std::string & modname, duint imageBase, duint imageSize, DiaValidationData_t* validationData);
private:
void loadPDBAsync();
bool loadSymbolsAsync();
bool loadSourceLinesAsync();
uint32_t findSourceFile(const std::string & fileName) const;