Skip to content
Permalink
Browse files

DBG: better heuristics for detecting the debuggee did not terminate a…

…fter 10 seconds
  • Loading branch information...
mrexodia committed Jul 7, 2019
1 parent 8a07bd2 commit 7212e853fbf05a70bea287c9c7cee843ae6677df
Showing with 76 additions and 46 deletions.
  1. +17 −7 src/dbg/commands/cmd-debug-control.cpp
  2. +51 −31 src/dbg/pdbdiafile.cpp
  3. +2 −1 src/dbg/pdbdiafile.h
  4. +6 −6 src/dbg/symbolsourcedia.cpp
  5. +0 −1 src/dbg/symbolsourcedia.h
@@ -161,6 +161,7 @@ bool cbDebugStop(int argc, char* argv[])
//history
HistoryClear();
DWORD BeginTick = GetTickCount();

This comment has been minimized.

Copy link
@codemanxpensive
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;
@@ -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;

std::vector<IDiaLineNumber*> lineNumbers;
ULONG lineCountStep = end - begin;
lineNumbers.resize(lineCountStep);

if(!files.count(sourceFileId))
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(!SUCCEEDED(hr))
continue;
if(cancelled)
{
for(ULONG m = n; m < fetched; m++)
lineNumbers[m]->Release();
return false;
}

CComPtr<IDiaLineNumber> lineNumberInfo;
lineNumberInfo.Attach(lineNumbers[n]);

BSTR fileName = nullptr;
hr = sourceFile->get_fileName(&fileName);
DWORD sourceFileId = 0;
hr = lineNumberInfo->get_sourceFileId(&sourceFileId);
if(!SUCCEEDED(hr))
continue;

files.insert({ sourceFileId, StringUtils::Utf16ToUtf8(fileName) });
SysFreeString(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;
DiaLineInfo_t lineInfo;
lineInfo.sourceFileId = sourceFileId;

hr = lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
if(!SUCCEEDED(hr))
continue;
hr = lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
if(!SUCCEEDED(hr))
continue;

hr = lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
if(!SUCCEEDED(hr))
continue;
hr = lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
if(!SUCCEEDED(hr))
continue;

lines.push_back(lineInfo);
lines.push_back(lineInfo);
}
}

return true;
@@ -8,6 +8,7 @@
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <atomic>

struct IDiaDataSource;
struct IDiaSession;
@@ -50,7 +51,7 @@ class PDBDiaFile

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);

@@ -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)
@@ -147,7 +147,6 @@ class SymbolSourceDIA : public SymbolSourceBase
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;

0 comments on commit 7212e85

Please sign in to comment.
You can’t perform that action at this time.