Merge branch 'development' into patch00000092
This commit is contained in:
commit
cf1498786c
|
|
@ -66,3 +66,6 @@
|
|||
0xC0150010 STATUS_SXS_INVALID_DEACTIVATION
|
||||
0xE0434352 CLR_EXCEPTION
|
||||
0xE06D7363 CPP_EH_EXCEPTION
|
||||
0xC06D0057 VCPP_EXCEPTION_ERROR_INVALID_PARAMETER
|
||||
0xC06D007E VCPP_EXCEPTION_ERROR_MOD_NOT_FOUND
|
||||
0xC06D007F VCPP_EXCEPTION_ERROR_PROC_NOT_FOUND
|
||||
|
|
@ -199,8 +199,10 @@ void TraceRecordManager::TraceExecute(duint address, duint size)
|
|||
}
|
||||
}
|
||||
|
||||
//See https://www.felixcloutier.com/x86/FXSAVE.html, max 512 bytes
|
||||
#define memoryContentSize 512
|
||||
|
||||
static void HandleCapstoneOperand(const Zydis & cp, int opindex, DISASM_ARGTYPE* argType, duint* value, unsigned char* memoryContent, unsigned char* memorySize)
|
||||
static void HandleCapstoneOperand(const Zydis & cp, int opindex, DISASM_ARGTYPE* argType, duint* value, unsigned char memoryContent[memoryContentSize], unsigned char* memorySize)
|
||||
{
|
||||
*value = cp.ResolveOpValue(opindex, [&cp](ZydisRegister reg)
|
||||
{
|
||||
|
|
@ -231,7 +233,7 @@ static void HandleCapstoneOperand(const Zydis & cp, int opindex, DISASM_ARGTYPE*
|
|||
*value += ThreadGetLocalBase(ThreadGetId(hActiveThread));
|
||||
}
|
||||
*memorySize = op.size / 8;
|
||||
if(DbgMemIsValidReadPtr(*value))
|
||||
if(*memorySize <= memoryContentSize && DbgMemIsValidReadPtr(*value))
|
||||
{
|
||||
MemRead(*value, memoryContent, max(op.size / 8, sizeof(duint)));
|
||||
}
|
||||
|
|
@ -253,23 +255,27 @@ void TraceRecordManager::TraceExecuteRecord(const Zydis & newInstruction)
|
|||
REGDUMPWORD newContext;
|
||||
//DISASM_INSTR newInstruction;
|
||||
DWORD newThreadId;
|
||||
duint newMemory[32];
|
||||
duint newMemoryAddress[32];
|
||||
duint oldMemory[32];
|
||||
const size_t memoryArrayCount = 32;
|
||||
duint newMemory[memoryArrayCount];
|
||||
duint newMemoryAddress[memoryArrayCount];
|
||||
duint oldMemory[memoryArrayCount];
|
||||
unsigned char newMemoryArrayCount = 0;
|
||||
DbgGetRegDumpEx(&newContext.registers, sizeof(REGDUMP));
|
||||
newThreadId = ThreadGetId(hActiveThread);
|
||||
// Don't try to resolve memory values for lea and nop instructions
|
||||
if(!(newInstruction.IsNop() || newInstruction.GetId() == ZYDIS_MNEMONIC_LEA))
|
||||
// Don't try to resolve memory values for invalid/lea/nop instructions
|
||||
if(newInstruction.Success() && !newInstruction.IsNop() && newInstruction.GetId() != ZYDIS_MNEMONIC_LEA)
|
||||
{
|
||||
DISASM_ARGTYPE argType;
|
||||
duint value;
|
||||
unsigned char memoryContent[128];
|
||||
unsigned char memoryContent[memoryContentSize];
|
||||
unsigned char memorySize;
|
||||
for(int i = 0; i < newInstruction.OpCount(); i++)
|
||||
{
|
||||
memset(memoryContent, 0, sizeof(memoryContent));
|
||||
HandleCapstoneOperand(newInstruction, i, &argType, &value, memoryContent, &memorySize);
|
||||
// check for overflow of the memory buffer
|
||||
if(newMemoryArrayCount * sizeof(duint) + memorySize > memoryArrayCount * sizeof(duint))
|
||||
continue;
|
||||
// TODO: Implicit memory access by push and pop instructions
|
||||
// TODO: Support memory value of ??? for invalid memory access
|
||||
if(argType == arg_memory)
|
||||
|
|
@ -305,7 +311,7 @@ void TraceRecordManager::TraceExecuteRecord(const Zydis & newInstruction)
|
|||
newMemoryArrayCount++;
|
||||
}
|
||||
//TODO: PUSHAD/POPAD
|
||||
assert(newMemoryArrayCount < 32);
|
||||
assert(newMemoryArrayCount < memoryArrayCount);
|
||||
}
|
||||
if(rtPrevInstAvailable)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,7 +31,18 @@ downslib_error downslib_download(const char* url,
|
|||
{
|
||||
DWORD dwLastError = GetLastError();
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bool doDelete = false;
|
||||
LARGE_INTEGER fileSize;
|
||||
if(dwLastError != ERROR_SUCCESS || (GetFileSizeEx(hFile, &fileSize) && fileSize.QuadPart == 0))
|
||||
{
|
||||
// an error occurred and now there is an empty or incomplete file that didn't exist before we came in
|
||||
doDelete = true;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
if(doDelete)
|
||||
DeleteFileW(filename);
|
||||
}
|
||||
if(hUrl != NULL)
|
||||
InternetCloseHandle(hUrl);
|
||||
if(hInternet != NULL)
|
||||
|
|
@ -39,7 +50,7 @@ downslib_error downslib_download(const char* url,
|
|||
SetLastError(dwLastError);
|
||||
});
|
||||
|
||||
hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
hFile = CreateFileW(filename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
return downslib_error::createfile;
|
||||
|
||||
|
|
@ -102,7 +113,10 @@ downslib_error downslib_download(const char* url,
|
|||
|
||||
// Call the callback to report progress and cancellation
|
||||
if(cb && !cb(read_bytes, total_bytes))
|
||||
{
|
||||
SetLastError(ERROR_OPERATION_ABORTED);
|
||||
return downslib_error::cancel;
|
||||
}
|
||||
|
||||
// Exit if nothing more to read
|
||||
if(dwRead == 0)
|
||||
|
|
@ -112,7 +126,11 @@ downslib_error downslib_download(const char* url,
|
|||
}
|
||||
|
||||
if(total_bytes > 0 && read_bytes != total_bytes)
|
||||
{
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return downslib_error::incomplete;
|
||||
}
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return downslib_error::ok;
|
||||
}
|
||||
|
|
@ -392,7 +392,10 @@ static int SymAutoComplete(const char* Search, char** Buffer, int MaxSymbols)
|
|||
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
auto modInfo = ModInfoFromAddr(base);
|
||||
if(modInfo && modInfo->symbols->isOpen())
|
||||
if(!modInfo)
|
||||
continue;
|
||||
|
||||
if(modInfo->symbols->isOpen())
|
||||
{
|
||||
modInfo->symbols->findSymbolsByPrefix(prefix, [Buffer, MaxSymbols, &count](const SymbolInfo & symInfo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1010,6 +1010,7 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
|
|||
bVerboseExceptionLogging = settingboolget("Engine", "VerboseExceptionLogging");
|
||||
bNoWow64SingleStepWorkaround = settingboolget("Engine", "NoWow64SingleStepWorkaround");
|
||||
bQueryWorkingSet = settingboolget("Misc", "QueryWorkingSet");
|
||||
bForceLoadSymbols = settingboolget("Misc", "ForceLoadSymbols");
|
||||
stackupdatesettings();
|
||||
|
||||
duint setting;
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ bool cbInstrExhandlers(int argc, char* argv[])
|
|||
|
||||
bool cbInstrExinfo(int argc, char* argv[])
|
||||
{
|
||||
const unsigned int MASK_FACILITY_VISUALCPP = 0x006D0000;
|
||||
auto info = getLastExceptionInfo();
|
||||
const auto & record = info.ExceptionRecord;
|
||||
dputs_untranslated("EXCEPTION_DEBUG_INFO:");
|
||||
|
|
@ -373,6 +374,14 @@ bool cbInstrExinfo(int argc, char* argv[])
|
|||
exceptionName = ErrorCodeToName(record.ExceptionCode);
|
||||
if(exceptionName.size())
|
||||
dprintf_untranslated(" ExceptionCode: %08X (%s)\n", record.ExceptionCode, exceptionName.c_str());
|
||||
else if((record.ExceptionCode & MASK_FACILITY_VISUALCPP) == MASK_FACILITY_VISUALCPP) //delayhlp.cpp
|
||||
{
|
||||
auto possibleError = record.ExceptionCode & 0xFFFF;
|
||||
exceptionName = ErrorCodeToName(possibleError);
|
||||
if(!exceptionName.empty())
|
||||
exceptionName = StringUtils::sprintf(" (Visual C++ %s)", exceptionName.c_str());
|
||||
dprintf_untranslated(" ExceptionCode: %08X%s\n", record.ExceptionCode, exceptionName.c_str());
|
||||
}
|
||||
else
|
||||
dprintf_untranslated(" ExceptionCode: %08X\n", record.ExceptionCode);
|
||||
dprintf_untranslated(" ExceptionFlags: %08X\n", record.ExceptionFlags);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ bool bNoForegroundWindow = false;
|
|||
bool bVerboseExceptionLogging = true;
|
||||
bool bNoWow64SingleStepWorkaround = false;
|
||||
bool bTraceBrowserNeedsUpdate = false;
|
||||
bool bForceLoadSymbols = false;
|
||||
duint DbgEvents = 0;
|
||||
duint maxSkipExceptionCount = 10000;
|
||||
HANDLE mProcHandle;
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ extern bool bIgnoreInconsistentBreakpoints;
|
|||
extern bool bNoForegroundWindow;
|
||||
extern bool bVerboseExceptionLogging;
|
||||
extern bool bNoWow64SingleStepWorkaround;
|
||||
extern bool bForceLoadSymbols;
|
||||
extern duint maxSkipExceptionCount;
|
||||
extern HANDLE mProcHandle;
|
||||
extern HANDLE mForegroundHandle;
|
||||
|
|
|
|||
|
|
@ -114,13 +114,18 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Note that we're loading this file because the debuggee did; that makes it at least somewhat plausible that we will also survive
|
||||
for(DWORD i = 0; i < exportDir->NumberOfFunctions; i++)
|
||||
{
|
||||
// It is possible the AddressOfFunctions contain zero RVAs. GetProcAddress for these ordinals returns zero.
|
||||
// "The reason for it is to assign a particular ordinal to a function." - NTCore
|
||||
if(!addressOfFunctions[i])
|
||||
continue;
|
||||
|
||||
Info.exports.emplace_back();
|
||||
auto & entry = Info.exports.back();
|
||||
entry.ordinal = i + exportDir->Base;
|
||||
entry.rva = addressOfFunctions[i];
|
||||
const auto entryVa = RvaToVa(FileMapVA, Info.headers, entry.rva);
|
||||
entry.forwarded = entryVa >= (ULONG64)exportDir;
|
||||
if(entry.forwarded && entryVa < (ULONG64)exportDir + exportDirSize)
|
||||
entry.forwarded = entryVa >= (ULONG64)exportDir && entryVa < (ULONG64)exportDir + exportDirSize;
|
||||
if(entry.forwarded)
|
||||
{
|
||||
auto forwardNameOffset = rva2offset(entry.rva);
|
||||
if(forwardNameOffset) // Silent ignore (1) by ntdll loader: invalid forward names or addresses of forward names
|
||||
|
|
@ -139,6 +144,13 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
}
|
||||
}
|
||||
|
||||
// give some kind of name to ordinal functions
|
||||
for(size_t i = 0; i < Info.exports.size(); i++)
|
||||
{
|
||||
if(Info.exports[i].name.empty())
|
||||
Info.exports[i].name = "Ordinal#" + std::to_string(Info.exports[i].ordinal);
|
||||
}
|
||||
|
||||
// prepare sorted vectors
|
||||
Info.exportsByName.resize(Info.exports.size());
|
||||
Info.exportsByRva.resize(Info.exports.size());
|
||||
|
|
@ -571,8 +583,6 @@ void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
strncat_s(pdbPath, ".pdb", _TRUNCATE);
|
||||
Info.pdbPaths.push_back(pdbPath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1119,7 +1129,7 @@ bool MODINFO::loadSymbols()
|
|||
{
|
||||
GuiSymbolLogAdd(StringUtils::sprintf("[DIA] Skipping non-existent PDB: %s\n", pdbPath.c_str()).c_str());
|
||||
}
|
||||
else if(symSource->loadPDB(pdbPath, base, size, &validationData))
|
||||
else if(symSource->loadPDB(pdbPath, base, size, bForceLoadSymbols ? nullptr : &validationData))
|
||||
{
|
||||
symSource->resizeSymbolBitmap(size);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,26 +146,16 @@ private:
|
|||
public:
|
||||
ScopedDiaType() : _sym(nullptr) {}
|
||||
ScopedDiaType(T* sym) : _sym(sym) {}
|
||||
~ScopedDiaType()
|
||||
{
|
||||
if(_sym != nullptr)
|
||||
{
|
||||
_sym->Release();
|
||||
}
|
||||
}
|
||||
~ScopedDiaType() { if(_sym != nullptr) _sym->Release(); }
|
||||
T** ref() { return &_sym; }
|
||||
T* operator->()
|
||||
{
|
||||
return _sym;
|
||||
}
|
||||
operator T* ()
|
||||
{
|
||||
return _sym;
|
||||
}
|
||||
T** operator&() { return ref(); }
|
||||
T* operator->() { return _sym; }
|
||||
operator T* () { return _sym; }
|
||||
void Attach(T* sym) { _sym = sym; }
|
||||
};
|
||||
|
||||
typedef ScopedDiaType<IDiaSymbol> ScopedDiaSymbol;
|
||||
typedef ScopedDiaType<IDiaEnumSymbols> ScopedDiaEnumSymbols;
|
||||
template<typename T>
|
||||
using CComPtr = ScopedDiaType<T>;
|
||||
|
||||
PDBDiaFile::PDBDiaFile() :
|
||||
m_stream(nullptr),
|
||||
|
|
@ -234,6 +224,13 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
GuiSymbolLogAdd("Unable to open PDB file.\n");
|
||||
return false;
|
||||
}
|
||||
/*std::vector<unsigned char> pdbData;
|
||||
if (!FileHelper::ReadAllData(StringUtils::Utf16ToUtf8(file), pdbData))
|
||||
{
|
||||
GuiSymbolLogAdd("Unable to open PDB file.\n");
|
||||
return false;
|
||||
}
|
||||
m_stream = SHCreateMemStream(pdbData.data(), pdbData.size());*/
|
||||
|
||||
if(validationData != nullptr)
|
||||
{
|
||||
|
|
@ -277,8 +274,8 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
|
||||
if(validationData != nullptr)
|
||||
{
|
||||
ScopedDiaType<IDiaSymbol> globalSym;
|
||||
hr = m_session->get_globalScope(globalSym.ref());
|
||||
CComPtr<IDiaSymbol> globalSym;
|
||||
hr = m_session->get_globalScope(&globalSym);
|
||||
if(testError(hr))
|
||||
{
|
||||
//??
|
||||
|
|
@ -320,6 +317,10 @@ bool PDBDiaFile::open(const wchar_t* file, uint64_t loadAddress, DiaValidationDa
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GuiSymbolLogAdd("Skipping PDB validation, expect invalid results!\n");
|
||||
}
|
||||
|
||||
if(loadAddress != 0)
|
||||
{
|
||||
|
|
@ -338,19 +339,25 @@ bool PDBDiaFile::close()
|
|||
{
|
||||
if(m_session)
|
||||
{
|
||||
m_session->Release();
|
||||
auto refcount = m_session->Release();
|
||||
if(refcount != 0)
|
||||
dprintf("Memory leaks in IDiaSession (refcount: %u)\n", refcount);
|
||||
m_session = nullptr;
|
||||
}
|
||||
|
||||
if(m_dataSource)
|
||||
{
|
||||
m_dataSource->Release();
|
||||
auto refcount = m_dataSource->Release();
|
||||
if(refcount != 0)
|
||||
dprintf("Memory leaks in IDiaDataSource (refcount: %u)\n", refcount);
|
||||
m_dataSource = nullptr;
|
||||
}
|
||||
|
||||
if(m_stream)
|
||||
{
|
||||
m_stream->Release();
|
||||
auto refcount = m_stream->Release();
|
||||
if(refcount != 0)
|
||||
dprintf("Memory leaks in IStream (refcount: %u)\n", refcount);
|
||||
m_stream = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -419,15 +426,15 @@ std::string PDBDiaFile::getSymbolUndecoratedNameString(IDiaSymbol* sym)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool PDBDiaFile::getFunctionLineNumbers(DWORD rva, ULONGLONG size, uint64_t imageBase, std::map<uint64_t, DiaLineInfo_t> & lines)
|
||||
bool PDBDiaFile::enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD lineNumber = 0;
|
||||
DWORD relativeVirtualAddress = 0;
|
||||
DWORD lineNumberEnd = 0;
|
||||
|
||||
ScopedDiaType<IDiaEnumLineNumbers> lineNumbersEnum;
|
||||
hr = m_session->findLinesByRVA(rva, static_cast<DWORD>(size), lineNumbersEnum.ref());
|
||||
CComPtr<IDiaEnumLineNumbers> lineNumbersEnum;
|
||||
hr = m_session->findLinesByRVA(rva, size, &lineNumbersEnum);
|
||||
if(!SUCCEEDED(hr))
|
||||
return false;
|
||||
|
||||
|
|
@ -439,57 +446,50 @@ bool PDBDiaFile::getFunctionLineNumbers(DWORD rva, ULONGLONG size, uint64_t imag
|
|||
if(lineCount == 0)
|
||||
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(LONG n = 0; n < fetched; n++)
|
||||
for(ULONG n = 0; n < fetched; n++)
|
||||
{
|
||||
ScopedDiaType<IDiaLineNumber> lineNumberInfo(lineNumbers[n]);
|
||||
CComPtr<IDiaLineNumber> lineNumberInfo;
|
||||
lineNumberInfo.Attach(lineNumbers[n]);
|
||||
|
||||
ScopedDiaType<IDiaSourceFile> sourceFile;
|
||||
hr = lineNumberInfo->get_sourceFile(sourceFile.ref());
|
||||
DWORD sourceFileId = 0;
|
||||
hr = lineNumberInfo->get_sourceFileId(&sourceFileId);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
hr = lineNumberInfo->get_lineNumber(&lineNumber);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
if(!files.count(sourceFileId))
|
||||
{
|
||||
CComPtr<IDiaSourceFile> sourceFile;
|
||||
hr = lineNumberInfo->get_sourceFile(&sourceFile);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
hr = lineNumberInfo->get_relativeVirtualAddress(&relativeVirtualAddress);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
BSTR fileName = nullptr;
|
||||
hr = sourceFile->get_fileName(&fileName);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
hr = lineNumberInfo->get_lineNumberEnd(&lineNumberEnd);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
DWORD segment = -1;
|
||||
hr = lineNumberInfo->get_addressSection(&segment);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
DWORD offset = -1;
|
||||
hr = lineNumberInfo->get_addressOffset(&offset);
|
||||
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.fileName = StringUtils::Utf16ToUtf8(fileName);
|
||||
lineInfo.lineNumber = lineNumber;
|
||||
lineInfo.offset = offset;
|
||||
lineInfo.segment = segment;
|
||||
lineInfo.virtualAddress = relativeVirtualAddress;
|
||||
lineInfo.sourceFileId = sourceFileId;
|
||||
|
||||
lines.emplace(lineInfo.virtualAddress, lineInfo);
|
||||
hr = lineNumberInfo->get_lineNumber(&lineInfo.lineNumber);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
SysFreeString(fileName);
|
||||
hr = lineNumberInfo->get_relativeVirtualAddress(&lineInfo.rva);
|
||||
if(!SUCCEEDED(hr))
|
||||
continue;
|
||||
|
||||
lines.push_back(lineInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -504,14 +504,14 @@ uint32_t getSymbolId(IDiaSymbol* sym)
|
|||
|
||||
bool PDBDiaFile::enumerateLexicalHierarchy(const Query_t & query)
|
||||
{
|
||||
ScopedDiaSymbol globalScope;
|
||||
CComPtr<IDiaSymbol> globalScope;
|
||||
IDiaSymbol* symbol = nullptr;
|
||||
ULONG celt = 0;
|
||||
HRESULT hr;
|
||||
DiaSymbol_t symbolInfo;
|
||||
bool res = true;
|
||||
|
||||
hr = m_session->get_globalScope(globalScope.ref());
|
||||
hr = m_session->get_globalScope(&globalScope);
|
||||
if(hr != S_OK)
|
||||
return false;
|
||||
|
||||
|
|
@ -525,14 +525,14 @@ bool PDBDiaFile::enumerateLexicalHierarchy(const Query_t & query)
|
|||
|
||||
// Enumerate compilands.
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = globalScope->findChildren(SymTagCompiland, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = globalScope->findChildren(SymTagCompiland, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
if(!enumerateCompilandScope(sym, context))
|
||||
{
|
||||
return false;
|
||||
|
|
@ -543,14 +543,14 @@ bool PDBDiaFile::enumerateLexicalHierarchy(const Query_t & query)
|
|||
|
||||
// Enumerate publics.
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = globalScope->findChildren(SymTagPublicSymbol, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = globalScope->findChildren(SymTagPublicSymbol, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
if(convertSymbolInfo(symbol, symbolInfo, context))
|
||||
{
|
||||
if(!context.callback(symbolInfo))
|
||||
|
|
@ -564,14 +564,14 @@ bool PDBDiaFile::enumerateLexicalHierarchy(const Query_t & query)
|
|||
|
||||
// Enumerate global functions.
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = globalScope->findChildren(SymTagFunction, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = globalScope->findChildren(SymTagFunction, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
if(convertSymbolInfo(sym, symbolInfo, context))
|
||||
{
|
||||
if(!context.callback(symbolInfo))
|
||||
|
|
@ -585,14 +585,14 @@ bool PDBDiaFile::enumerateLexicalHierarchy(const Query_t & query)
|
|||
|
||||
// Enumerate global data.
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = globalScope->findChildren(SymTagData, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = globalScope->findChildren(SymTagData, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
if(convertSymbolInfo(sym, symbolInfo, context))
|
||||
{
|
||||
if(!context.callback(symbolInfo))
|
||||
|
|
@ -635,11 +635,11 @@ bool PDBDiaFile::findSymbolRVA(uint64_t address, DiaSymbol_t & sym, DiaSymbolTyp
|
|||
}
|
||||
|
||||
long disp = 0;
|
||||
hr = m_session->findSymbolByRVAEx(address, tag, &symbol, &disp);
|
||||
hr = m_session->findSymbolByRVAEx((DWORD)address, tag, &symbol, &disp);
|
||||
if(hr != S_OK)
|
||||
return false;
|
||||
|
||||
ScopedDiaSymbol scopedSym(symbol);
|
||||
CComPtr<IDiaSymbol> scopedSym(symbol);
|
||||
|
||||
sym.disp = disp;
|
||||
|
||||
|
|
@ -665,14 +665,14 @@ bool PDBDiaFile::enumerateCompilandScope(IDiaSymbol* compiland, InternalQueryCon
|
|||
uint32_t symId = getSymbolId(compiland);
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = compiland->findChildren(SymTagFunction, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = compiland->findChildren(SymTagFunction, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -689,14 +689,14 @@ bool PDBDiaFile::enumerateCompilandScope(IDiaSymbol* compiland, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = compiland->findChildren(SymTagData, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = compiland->findChildren(SymTagData, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -715,14 +715,14 @@ bool PDBDiaFile::enumerateCompilandScope(IDiaSymbol* compiland, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = compiland->findChildren(SymTagBlock, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = compiland->findChildren(SymTagBlock, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -741,14 +741,14 @@ bool PDBDiaFile::enumerateCompilandScope(IDiaSymbol* compiland, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
|
||||
hr = compiland->findChildren(SymTagLabel, nullptr, nsNone, enumSymbols.ref());
|
||||
hr = compiland->findChildren(SymTagLabel, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -793,13 +793,13 @@ bool PDBDiaFile::processFunctionSymbol(IDiaSymbol* functionSym, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagData, nullptr, nsNone, enumSymbols.ref());
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagData, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -821,13 +821,13 @@ bool PDBDiaFile::processFunctionSymbol(IDiaSymbol* functionSym, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagBlock, nullptr, nsNone, enumSymbols.ref());
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagBlock, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -846,13 +846,13 @@ bool PDBDiaFile::processFunctionSymbol(IDiaSymbol* functionSym, InternalQueryCon
|
|||
}
|
||||
|
||||
{
|
||||
ScopedDiaEnumSymbols enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagLabel, nullptr, nsNone, enumSymbols.ref());
|
||||
CComPtr<IDiaEnumSymbols> enumSymbols;
|
||||
hr = functionSym->findChildren(SymTagLabel, nullptr, nsNone, &enumSymbols);
|
||||
if(hr == S_OK)
|
||||
{
|
||||
while((hr = enumSymbols->Next(1, &symbol, &celt)) == S_OK && celt == 1)
|
||||
{
|
||||
ScopedDiaSymbol sym(symbol);
|
||||
CComPtr<IDiaSymbol> sym(symbol);
|
||||
|
||||
hr = sym->get_symTag(&symTagType);
|
||||
|
||||
|
|
@ -882,8 +882,8 @@ bool PDBDiaFile::resolveSymbolSize(IDiaSymbol* symbol, uint64_t & size, uint32_t
|
|||
|
||||
if(symTag == SymTagData)
|
||||
{
|
||||
ScopedDiaSymbol symType;
|
||||
hr = symbol->get_type(symType.ref());
|
||||
CComPtr<IDiaSymbol> symType;
|
||||
hr = symbol->get_type(&symType);
|
||||
|
||||
if(hr == S_OK && symType != nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
bool close();
|
||||
|
||||
bool getFunctionLineNumbers(DWORD rva, ULONGLONG size, uint64_t imageBase, std::map<uint64_t, DiaLineInfo_t> & lines);
|
||||
bool enumerateLineNumbers(uint32_t rva, uint32_t size, std::vector<DiaLineInfo_t> & lines, std::map<DWORD, std::string> & files);
|
||||
|
||||
bool enumerateLexicalHierarchy(const Query_t & query);
|
||||
|
||||
|
|
|
|||
|
|
@ -75,11 +75,9 @@ struct DiaSymbol_t
|
|||
|
||||
struct DiaLineInfo_t
|
||||
{
|
||||
std::string fileName;
|
||||
DWORD sourceFileId;
|
||||
DWORD lineNumber;
|
||||
uint32_t offset;
|
||||
uint32_t segment;
|
||||
uint64_t virtualAddress;
|
||||
DWORD rva;
|
||||
};
|
||||
|
||||
#endif // PDBDIATYPES_H_
|
||||
|
|
@ -195,6 +195,8 @@ static void stackgetsuspectedcallstack(duint csp, std::vector<CALLSTACKENTRY> &
|
|||
{
|
||||
duint size;
|
||||
duint base = MemFindBaseAddr(csp, &size);
|
||||
if(!base)
|
||||
return;
|
||||
duint end = base + size;
|
||||
size = end - csp;
|
||||
Memory<duint*> stackdata(size);
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ bool SymbolSourceDIA::loadSymbolsAsync()
|
|||
PDBDiaFile::Query_t query;
|
||||
query.collectSize = true;
|
||||
query.collectUndecoratedNames = true;
|
||||
query.callback = [&](DiaSymbol_t & sym)->bool
|
||||
query.callback = [&](DiaSymbol_t & sym) -> bool
|
||||
{
|
||||
if(_requiresShutdown)
|
||||
return false;
|
||||
|
|
@ -243,37 +243,41 @@ bool SymbolSourceDIA::loadSourceLinesAsync()
|
|||
|
||||
DWORD lineLoadStart = GetTickCount();
|
||||
|
||||
const size_t rangeSize = 1024 * 1024;
|
||||
const uint32_t rangeSize = 1024 * 1024 * 10;
|
||||
|
||||
std::map<DWORD, String> files;
|
||||
|
||||
for(duint rva = 0; rva < _imageSize; rva += rangeSize)
|
||||
{
|
||||
if(_requiresShutdown)
|
||||
return false;
|
||||
|
||||
std::map<uint64_t, DiaLineInfo_t> lines;
|
||||
std::vector<DiaLineInfo_t> lines;
|
||||
|
||||
bool res = pdb.getFunctionLineNumbers(rva, rangeSize, _imageBase, lines);
|
||||
bool res = pdb.enumerateLineNumbers(uint32_t(rva), rangeSize, lines, files);
|
||||
for(const auto & line : lines)
|
||||
{
|
||||
if(_requiresShutdown)
|
||||
return false;
|
||||
|
||||
const auto & info = line.second;
|
||||
auto it = _lines.find(info.virtualAddress);
|
||||
const auto & info = line;
|
||||
auto it = _lines.find(info.rva);
|
||||
if(it != _lines.end())
|
||||
continue;
|
||||
|
||||
CachedLineInfo lineInfo;
|
||||
lineInfo.rva = info.virtualAddress;
|
||||
lineInfo.rva = info.rva;
|
||||
lineInfo.lineNumber = info.lineNumber;
|
||||
|
||||
auto idx = findSourceFile(info.fileName);
|
||||
if(idx == -1)
|
||||
auto sourceFileId = info.sourceFileId;
|
||||
auto found = _sourceIdMap.find(sourceFileId);
|
||||
if(found == _sourceIdMap.end())
|
||||
{
|
||||
idx = _sourceFiles.size();
|
||||
_sourceFiles.push_back(info.fileName);
|
||||
auto idx = _sourceFiles.size();
|
||||
_sourceFiles.push_back(files[sourceFileId]);
|
||||
found = _sourceIdMap.insert({ sourceFileId, uint32_t(idx) }).first;
|
||||
}
|
||||
lineInfo.sourceFileIdx = idx;
|
||||
lineInfo.sourceFileIdx = found->second;
|
||||
|
||||
_lockLines.lock();
|
||||
|
||||
|
|
@ -312,7 +316,7 @@ uint32_t SymbolSourceDIA::findSourceFile(const std::string & fileName) const
|
|||
for(uint32_t n = 0; n < _sourceFiles.size(); n++)
|
||||
{
|
||||
const String & str = _sourceFiles[n];
|
||||
if(stricmp(str.c_str(), fileName.c_str()) == 0)
|
||||
if(_stricmp(str.c_str(), fileName.c_str()) == 0)
|
||||
{
|
||||
idx = n;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ private: //line info
|
|||
//TODO: make this source file stuff smarter
|
||||
std::vector<CachedLineInfo> _linesData;
|
||||
std::map<duint, size_t> _lines; //addr -> line
|
||||
std::vector<String> _sourceFiles;
|
||||
std::vector<String> _sourceFiles; // uniqueId + name
|
||||
std::map<DWORD, uint32_t> _sourceIdMap; //uniqueId -> index in _sourceFiles
|
||||
std::vector<std::map<int, size_t>> _sourceLines; //uses index in _sourceFiles
|
||||
|
||||
private: //general
|
||||
|
|
|
|||
|
|
@ -1,5 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Duncan Ogilvie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef APPEARANCEDIALOG_H
|
||||
#define APPEARANCEDIALOG_H
|
||||
|
||||
#include <QAction>
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
|
||||
|
|
|
|||
|
|
@ -502,6 +502,7 @@ RegistersView::RegistersView(CPUWidget* parent) : QScrollArea(parent), mVScrollO
|
|||
wCM_ToggleValue = setupAction(DIcon("register_toggle.png"), tr("Toggle"), this);
|
||||
wCM_Undo = setupAction(DIcon("undo.png"), tr("Undo"), this);
|
||||
wCM_CopyToClipboard = setupAction(DIcon("copy.png"), tr("Copy value to clipboard"), this);
|
||||
wCM_CopyFloatingPointValueToClipboard = setupAction(DIcon("copy.png"), tr("Copy floating point value to clipboard"), this);
|
||||
wCM_CopySymbolToClipboard = setupAction(DIcon("pdb.png"), tr("Copy Symbol Value to Clipboard"), this);
|
||||
wCM_CopyAll = setupAction(DIcon("copy-alt.png"), tr("Copy all registers"), this);
|
||||
wCM_FollowInDisassembly = new QAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in Disassembler"), this);
|
||||
|
|
@ -1346,6 +1347,7 @@ RegistersView::RegistersView(CPUWidget* parent) : QScrollArea(parent), mVScrollO
|
|||
connect(wCM_ToggleValue, SIGNAL(triggered()), this, SLOT(onToggleValueAction()));
|
||||
connect(wCM_Undo, SIGNAL(triggered()), this, SLOT(onUndoAction()));
|
||||
connect(wCM_CopyToClipboard, SIGNAL(triggered()), this, SLOT(onCopyToClipboardAction()));
|
||||
connect(wCM_CopyFloatingPointValueToClipboard, SIGNAL(triggered()), this, SLOT(onCopyFloatingPointToClipboardAction()));
|
||||
connect(wCM_CopySymbolToClipboard, SIGNAL(triggered()), this, SLOT(onCopySymbolToClipboardAction()));
|
||||
connect(wCM_CopyAll, SIGNAL(triggered()), this, SLOT(onCopyAllAction()));
|
||||
connect(wCM_FollowInDisassembly, SIGNAL(triggered()), this, SLOT(onFollowInDisassembly()));
|
||||
|
|
@ -2855,6 +2857,12 @@ void RegistersView::onCopyToClipboardAction()
|
|||
clipboard->setText(GetRegStringValueFromValue(mSelected, registerValue(&wRegDumpStruct, mSelected)));
|
||||
}
|
||||
|
||||
void RegistersView::onCopyFloatingPointToClipboardAction()
|
||||
{
|
||||
QClipboard* clipboard = QApplication::clipboard();
|
||||
clipboard->setText(ToLongDoubleString(((X87FPUREGISTER*) registerValue(&wRegDumpStruct, mSelected))->data));
|
||||
}
|
||||
|
||||
void RegistersView::onCopySymbolToClipboardAction()
|
||||
{
|
||||
if(mLABELDISPLAY.contains(mSelected))
|
||||
|
|
@ -3205,6 +3213,10 @@ void RegistersView::displayCustomContextMenuSlot(QPoint pos)
|
|||
}
|
||||
|
||||
wMenu.addAction(wCM_CopyToClipboard);
|
||||
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
{
|
||||
wMenu.addAction(wCM_CopyFloatingPointValueToClipboard);
|
||||
}
|
||||
wMenu.addAction(wCM_CopyAll);
|
||||
if(mLABELDISPLAY.contains(mSelected))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ protected slots:
|
|||
void onToggleValueAction();
|
||||
void onUndoAction();
|
||||
void onCopyToClipboardAction();
|
||||
void onCopyFloatingPointToClipboardAction();
|
||||
void onCopySymbolToClipboardAction();
|
||||
void onCopyAllAction();
|
||||
void onFollowInDisassembly();
|
||||
|
|
@ -274,6 +275,7 @@ private:
|
|||
QAction* wCM_ToggleValue;
|
||||
QAction* wCM_Undo;
|
||||
QAction* wCM_CopyToClipboard;
|
||||
QAction* wCM_CopyFloatingPointValueToClipboard;
|
||||
QAction* wCM_CopySymbolToClipboard;
|
||||
QAction* wCM_CopyAll;
|
||||
QAction* wCM_FollowInDisassembly;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef WORDEDITDIALOG_H
|
||||
#define WORDEDITDIALOG_H
|
||||
|
||||
#include <QValidator>
|
||||
#include <QDialog>
|
||||
#include <QPushButton>
|
||||
#include "Imports.h"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent)
|
|||
mRvaDisplayBase = 0;
|
||||
mRvaDisplayEnabled = false;
|
||||
|
||||
mAutoDisassemblyFollowSelection = false;
|
||||
|
||||
int maxModuleSize = (int)ConfigUint("Disassembler", "MaxModuleSize");
|
||||
mDisasm = new QBeaEngine(maxModuleSize);
|
||||
mHighlightingMode = false;
|
||||
|
|
@ -564,6 +566,19 @@ void TraceBrowser::setupRightClickContextMenu()
|
|||
return true;
|
||||
});
|
||||
mMenuBuilder->addMenu(makeMenu(tr("Information")), infoMenu);
|
||||
|
||||
|
||||
QAction* toggleAutoDisassemblyFollowSelection = makeAction(tr("Toggle Auto Disassembly Scroll (off)"), SLOT(toggleAutoDisassemblyFollowSelection()));
|
||||
mMenuBuilder->addAction(toggleAutoDisassemblyFollowSelection, [this, toggleAutoDisassemblyFollowSelection](QMenu*)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
if(mAutoDisassemblyFollowSelection)
|
||||
toggleAutoDisassemblyFollowSelection->setText(tr("Toggle Auto Disassembly Scroll (on)"));
|
||||
else
|
||||
toggleAutoDisassemblyFollowSelection->setText(tr("Toggle Auto Disassembly Scroll (off)"));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void TraceBrowser::contextMenuEvent(QContextMenuEvent* event)
|
||||
|
|
@ -628,6 +643,10 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event)
|
|||
setSingleSelection(index);
|
||||
mHistory.addVaToHistory(index);
|
||||
updateViewport();
|
||||
|
||||
if(mAutoDisassemblyFollowSelection)
|
||||
followDisassemblySlot();
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
|
@ -756,6 +775,9 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event)
|
|||
makeVisible(visibleindex);
|
||||
mHistory.addVaToHistory(visibleindex);
|
||||
updateViewport();
|
||||
|
||||
if(mAutoDisassemblyFollowSelection)
|
||||
followDisassemblySlot();
|
||||
}
|
||||
else
|
||||
AbstractTableView::keyPressEvent(event);
|
||||
|
|
@ -1373,3 +1395,8 @@ void TraceBrowser::updateSlot()
|
|||
reloadData();
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBrowser::toggleAutoDisassemblyFollowSelectionSlot()
|
||||
{
|
||||
mAutoDisassemblyFollowSelection = !mAutoDisassemblyFollowSelection;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ private:
|
|||
CapstoneTokenizer::SingleToken mHighlightToken;
|
||||
bool mHighlightingMode;
|
||||
bool mPermanentHighlightingMode;
|
||||
bool mAutoDisassemblyFollowSelection;
|
||||
|
||||
TraceFileReader* mTraceFile;
|
||||
QBeaEngine* mDisasm;
|
||||
|
|
@ -131,6 +132,8 @@ public slots:
|
|||
void searchMemRefSlot();
|
||||
|
||||
void updateSlot(); //debug
|
||||
|
||||
void toggleAutoDisassemblyFollowSelectionSlot();
|
||||
};
|
||||
|
||||
#endif //TRACEBROWSER_H
|
||||
|
|
|
|||
Loading…
Reference in New Issue