From d5e5c75aed81d3a4ccc7d294b00c46c0a934b3c0 Mon Sep 17 00:00:00 2001 From: Alex Alabuzhev Date: Sat, 20 Feb 2016 14:01:51 +0000 Subject: [PATCH] 1. More 4548: more correct stack on x86, source file/line in stack & main dialog. 2. Process forward slash in UnquoteExternal() too. --- far/changelog | 8 ++- far/farexcpt.cpp | 31 +++++------ far/imports.cpp | 33 ++++++++--- far/imports.hpp | 5 +- far/strmix.cpp | 2 +- far/tracer.cpp | 140 ++++++++++++++++++++++++++++++++++++----------- far/tracer.hpp | 26 ++++++--- far/vbuild.m4 | 2 +- 8 files changed, 176 insertions(+), 71 deletions(-) diff --git a/far/changelog b/far/changelog index 48474473ff..79211f7c92 100644 --- a/far/changelog +++ b/far/changelog @@ -1,4 +1,10 @@ -w17 20.02.2016 15:03:22 +0300 - build 4556 +drkns 20.02.2016 15:56:08 +0200 - build 4557 + +1. Продолжение 4548: показываем более правильный стек на x86, показываем source file/line в стеке и в основном диалоге. + +2. В UnquoteExternal() учтём прямой слеш тоже. + +w17 20.02.2016 15:03:22 +0300 - build 4556 1. Уточнение 4523. Учтём "D:\Path Name"\ в UnquoteExternal() diff --git a/far/farexcpt.cpp b/far/farexcpt.cpp index e55dd7da92..bdf38fbc65 100644 --- a/far/farexcpt.cpp +++ b/far/farexcpt.cpp @@ -59,9 +59,8 @@ void CreatePluginStartupInfo(const Plugin *pPlugin, PluginStartupInfo *PSI, FarS #define LAST_BUTTON 14 -static void ShowStackTraceImpl(const std::vector& Trace) +static void ShowStackTraceImpl(const std::vector& Symbols) { - const auto Symbols = tracer::GetSymbols(Trace); if (Global && Global->WindowManager && !Global->WindowManager->ManagerIsDown()) { Message(MSG_WARNING | MSG_LEFTALIGN, MSG(MExcTrappedException), Symbols, make_vector(MSG(MOk))); @@ -79,7 +78,7 @@ static void ShowStackTraceImpl(const std::vector& Trace) template void ShowStackTrace(const T& e) { - return ShowStackTraceImpl(tracer::GetInstance()->get(e)); + return ShowStackTraceImpl(tracer::get(e)); } intptr_t ExcDlgProc(Dialog* Dlg,intptr_t Msg,intptr_t Param1,void* Param2) @@ -131,7 +130,7 @@ intptr_t ExcDlgProc(Dialog* Dlg,intptr_t Msg,intptr_t Param1,void* Param2) return FALSE; case 12: // stack - ShowStackTrace(reinterpret_cast(Dlg->SendMessage(DM_GETDLGDATA, 0, nullptr))); + ShowStackTrace(reinterpret_cast(Dlg->SendMessage(DM_GETDLGDATA, 0, nullptr))); return FALSE; } } @@ -156,24 +155,24 @@ enum reply reply_ignore, }; -static reply ExcDialog(const string& ModuleName, LPCWSTR Exception, const EXCEPTION_RECORD* xr) +static reply ExcDialog(const string& ModuleName, LPCWSTR Exception, const EXCEPTION_POINTERS* xp) { // TODO: Far Dialog is not the best choice for exception reporting // replace with something trivial - const auto strAddr = L"0x" + to_hex_wstring(reinterpret_cast(xr->ExceptionAddress)); + const auto strAddr = tracer::get(xp->ExceptionRecord->ExceptionAddress); FarDialogItem EditDlgData[]= { {DI_DOUBLEBOX,3,1,76,8,0,nullptr,nullptr,0,MSG(MExcTrappedException)}, {DI_TEXT, 5,2, 17,2,0,nullptr,nullptr,0,MSG(MExcException)}, - {DI_TEXT, 18,2, 70,2,0,nullptr,nullptr,0,Exception}, + {DI_TEXT, 18,2, 75,2,0,nullptr,nullptr,0,Exception}, {DI_TEXT, 5,3, 17,3,0,nullptr,nullptr,0,MSG(MExcAddress)}, - {DI_TEXT, 18,3, 70,3,0,nullptr,nullptr,0,strAddr.data()}, + {DI_EDIT, 18,3, 75,3,0,nullptr,nullptr,DIF_READONLY|DIF_SELECTONENTRY,strAddr.data()}, {DI_TEXT, 5,4, 17,4,0,nullptr,nullptr,0,MSG(MExcFunction)}, - {DI_TEXT, 18,4, 70,4,0,nullptr,nullptr,0,gFrom}, + {DI_TEXT, 18,4, 75,4,0,nullptr,nullptr,0,gFrom}, {DI_TEXT, 5,5, 17,5,0,nullptr,nullptr,0,MSG(MExcModule)}, - {DI_EDIT, 18,5, 70,5,0,nullptr,nullptr,DIF_READONLY|DIF_SELECTONENTRY,ModuleName.data()}, + {DI_EDIT, 18,5, 75,5,0,nullptr,nullptr,DIF_READONLY|DIF_SELECTONENTRY,ModuleName.data()}, {DI_TEXT, -1,6, 0,6,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_BUTTON, 0,7, 0,7,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_FOCUS|DIF_CENTERGROUP, MSG(PluginModule? MExcUnload : MExcTerminate)}, {DI_BUTTON, 0,7, 0,7,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MExcDebugger)}, @@ -182,7 +181,7 @@ static reply ExcDialog(const string& ModuleName, LPCWSTR Exception, const EXCEPT {DI_BUTTON, 0,7, 0,7,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MIgnore)}, }; auto EditDlg = MakeDialogItemsEx(EditDlgData); - const auto Dlg = Dialog::create(EditDlg, ExcDlgProc, const_cast(reinterpret_cast(xr))); + const auto Dlg = Dialog::create(EditDlg, ExcDlgProc, const_cast(reinterpret_cast(xp))); Dlg->SetDialogMode(DMODE_WARNINGSTYLE|DMODE_NOPLUGINS); Dlg->SetPosition(-1, -1, 80, 10); Dlg->Process(); @@ -201,9 +200,9 @@ static reply ExcDialog(const string& ModuleName, LPCWSTR Exception, const EXCEPT } } -static void ExcDump(const string& ModuleName, LPCWSTR Exception, const EXCEPTION_RECORD* xr) +static void ExcDump(const string& ModuleName, LPCWSTR Exception, const EXCEPTION_POINTERS* xp) { - const auto strAddr = L"0x" + to_hex_wstring(reinterpret_cast(xr->ExceptionAddress)); + const auto strAddr = tracer::get(xp->ExceptionRecord->ExceptionAddress); string Msg[4]; if (LanguageLoaded()) @@ -229,7 +228,7 @@ static void ExcDump(const string& ModuleName, LPCWSTR Exception, const EXCEPTION std::wcerr << Dump << std::endl; - ShowStackTrace(xr); + ShowStackTrace(xp); } template @@ -429,12 +428,12 @@ static bool ProcessSEHExceptionImpl(EXCEPTION_POINTERS *xp) if (Global && Global->WindowManager && !Global->WindowManager->ManagerIsDown()) { - MsgCode = ExcDialog(strFileName, Exception, xr); + MsgCode = ExcDialog(strFileName, Exception, xp); ShowMessages=TRUE; } else { - ExcDump(strFileName, Exception, xr); + ExcDump(strFileName, Exception, xp); } if (ShowMessages && !PluginModule) diff --git a/far/imports.cpp b/far/imports.cpp index fae848641e..4cef0fa5b8 100644 --- a/far/imports.cpp +++ b/far/imports.cpp @@ -85,7 +85,6 @@ ImportedFunctions::ImportedFunctions(): INIT_IMPORT(m_kernel32, TzSpecificLocalTimeToSystemTime), INIT_IMPORT(m_kernel32, AddVectoredExceptionHandler), INIT_IMPORT(m_kernel32, RemoveVectoredExceptionHandler), - INIT_IMPORT(m_kernel32, RtlCaptureStackBackTrace), INIT_IMPORT(m_shell32, SHCreateAssociationRegistration), @@ -104,9 +103,12 @@ ImportedFunctions::ImportedFunctions(): INIT_IMPORT(m_netapi32, NetDfsGetInfo), INIT_IMPORT(m_dbghelp, MiniDumpWriteDump), + INIT_IMPORT(m_dbghelp, StackWalk64), INIT_IMPORT(m_dbghelp, SymInitialize), INIT_IMPORT(m_dbghelp, SymCleanup), - INIT_IMPORT(m_dbghelp, SymFromAddr) + INIT_IMPORT(m_dbghelp, SymFromAddr), + INIT_IMPORT(m_dbghelp, SymSetOptions), + INIT_IMPORT(m_dbghelp, SymGetLineFromAddr64) #undef INIT_IMPORT { @@ -301,13 +303,6 @@ ULONG WINAPI ImportedFunctions::stub_RemoveVectoredExceptionHandler(PVOID Handle return 0; } -USHORT WINAPI ImportedFunctions::stub_RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID BackTrace, PULONG BackTraceHash) -{ - // TODO: log - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - // shell32 HRESULT STDAPICALLTYPE ImportedFunctions::stub_SHCreateAssociationRegistration(REFIID riid, void ** ppv) { @@ -388,6 +383,12 @@ BOOL WINAPI ImportedFunctions::stub_MiniDumpWriteDump(HANDLE Process, DWORD Proc return FALSE; } +BOOL WINAPI ImportedFunctions::stub_StackWalk64(DWORD MachineType, HANDLE Process, HANDLE Thread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + BOOL WINAPI ImportedFunctions::stub_SymInitialize(HANDLE Process, PCSTR UserSearchPath, BOOL InvadeProcess) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); @@ -405,3 +406,17 @@ BOOL WINAPI ImportedFunctions::stub_SymFromAddr(HANDLE Process, DWORD64 Address, SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } + +DWORD WINAPI ImportedFunctions::stub_SymSetOptions(DWORD SymOptions) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +BOOL WINAPI ImportedFunctions::stub_SymGetLineFromAddr64(HANDLE Process, DWORD64 Addr, PDWORD Displacement, PIMAGEHLP_LINE64 Line) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + + diff --git a/far/imports.hpp b/far/imports.hpp index d5c7eb32aa..eb495d563a 100644 --- a/far/imports.hpp +++ b/far/imports.hpp @@ -110,7 +110,6 @@ public: const unique_function_pointer= 3 && strStr[len-1] == L'\\' && strStr[len-2] == L'\"') // '"D:\Path Name"\' + else if (len >= 3 && IsSlash(strStr[len-1]) && strStr[len-2] == L'\"') // '"D:\Path Name"\' { strStr.erase(len-2, 1); strStr.erase(0, 1); diff --git a/far/tracer.cpp b/far/tracer.cpp index 73a1c0ff06..713c81d8c7 100644 --- a/far/tracer.cpp +++ b/far/tracer.cpp @@ -34,35 +34,67 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tracer.hpp" #include "imports.hpp" -static std::vector GetBackTrace() +static std::vector GetBackTrace(const EXCEPTION_POINTERS* ExceptionInfo) { - // ## Windows Server 2003 and Windows XP: - // ## The sum of the FramesToSkip and FramesToCapture parameters must be less than 63. - const int MaxCallers = 62; - std::vector Result(MaxCallers); - auto FramesCount = Imports().RtlCaptureStackBackTrace(0, MaxCallers, Result.data(), nullptr); - Result.resize(FramesCount); + std::vector Result; + + // StackWalk64() may modify context record passed to it, so we will use a copy. + auto ContextRecord = *ExceptionInfo->ContextRecord; + STACKFRAME64 StackFrame = {}; +#if defined(_WIN64) + int machine_type = IMAGE_FILE_MACHINE_AMD64; + StackFrame.AddrPC.Offset = ContextRecord.Rip; + StackFrame.AddrFrame.Offset = ContextRecord.Rbp; + StackFrame.AddrStack.Offset = ContextRecord.Rsp; +#else + int machine_type = IMAGE_FILE_MACHINE_I386; + StackFrame.AddrPC.Offset = ContextRecord.Eip; + StackFrame.AddrFrame.Offset = ContextRecord.Ebp; + StackFrame.AddrStack.Offset = ContextRecord.Esp; +#endif + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrFrame.Mode = AddrModeFlat; + StackFrame.AddrStack.Mode = AddrModeFlat; + + block_ptr Symbol(sizeof(SYMBOL_INFO) + 256); + Symbol->MaxNameLen = 255; + Symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + + while (Imports().StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), &StackFrame, &ContextRecord, nullptr, nullptr, nullptr, nullptr)) + { + Result.push_back((const void*)StackFrame.AddrPC.Offset); + } + return Result; } -std::vector tracer::GetSymbols(const std::vector& BackTrace) +static std::vector GetSymbols(const std::vector& BackTrace) { std::vector Result; const auto Process = GetCurrentProcess(); - if (!Imports().SymInitialize(Process, nullptr, TRUE)) - return Result; - SCOPE_EXIT{ Imports().SymCleanup(Process); }; - - const auto MaxNameLen = 2047; + const auto MaxNameLen = MAX_SYM_NAME; block_ptr Symbol(sizeof(SYMBOL_INFO) + MaxNameLen + 1); Symbol->SizeOfStruct = sizeof(SYMBOL_INFO); Symbol->MaxNameLen = MaxNameLen; + + Imports().SymSetOptions(SYMOPT_LOAD_LINES); + IMAGEHLP_LINE64 Line = { sizeof(Line) }; + DWORD Displacement; + std::wostringstream Stream; - for (size_t i = 0, size = BackTrace.size(); i != size; ++i) + FOR(const auto i, BackTrace) { - Imports().SymFromAddr(Process, reinterpret_cast(BackTrace[i]), nullptr, Symbol.get()); - Stream << i << ": " << BackTrace[i] << " " << Symbol->Name << " - 0x" << Symbol->Address; + Stream << L"0x" << i; + const auto Address = reinterpret_cast(i); + if (Imports().SymFromAddr(Process, Address, nullptr, Symbol.get())) + { + Stream << " " << Symbol->Name; + } + if (Imports().SymGetLineFromAddr64(Process, Address, &Displacement, &Line)) + { + Stream << L" (" << Line.FileName << L":" << Line.LineNumber << L")"; + } Result.emplace_back(Stream.str()); Stream.str(string()); } @@ -71,11 +103,11 @@ std::vector tracer::GetSymbols(const std::vector& BackTrace) LONG WINAPI StackLogger(EXCEPTION_POINTERS *xp) { - if (xp->ExceptionRecord->ExceptionCode == 0xE06D7363) // MS C++ exception - tracer::GetInstance()->store(*reinterpret_cast(xp->ExceptionRecord->ExceptionInformation[1]), GetBackTrace()); - else - tracer::GetInstance()->store(xp->ExceptionRecord, GetBackTrace()); - + static const auto MSCPPExceptionCode = 0xE06D7363; + if (xp->ExceptionRecord->ExceptionCode == MSCPPExceptionCode) + { + tracer::GetInstance()->store(*reinterpret_cast(xp->ExceptionRecord->ExceptionInformation[1]), xp); + } return EXCEPTION_CONTINUE_SEARCH; } @@ -97,27 +129,71 @@ tracer::~tracer() sTracer = nullptr; } - -void tracer::store(const EXCEPTION_RECORD* Record, std::vector&& BackTrace) +void tracer::store(const std::exception& e, const EXCEPTION_POINTERS* ExceptionInfo) { SCOPED_ACTION(CriticalSectionLock)(m_CS); - m_SehMap.insert(std::make_pair(Record, std::move(BackTrace))); + exception_context Context = { *ExceptionInfo->ExceptionRecord, *ExceptionInfo->ContextRecord }; + m_StdMap.insert(std::make_pair(&e, Context)); } -void tracer::store(const std::exception& e, std::vector&& BackTrace) +bool tracer::get_context(const std::exception& e, exception_context& Context) const { SCOPED_ACTION(CriticalSectionLock)(m_CS); - m_StdMap.insert(std::make_pair(&e, std::move(BackTrace))); + auto Iter = m_StdMap.find(&e); + if (Iter == m_StdMap.end()) + { + return false; + } + Context = Iter->second; + return true; } -std::vector tracer::get(const EXCEPTION_RECORD* Record) +std::vector tracer::get(const std::exception& e) { - SCOPED_ACTION(CriticalSectionLock)(m_CS); - return m_SehMap[Record]; + exception_context Context; + if (!tracer::GetInstance()->get_context(e, Context)) + { + return std::vector(); + } + EXCEPTION_POINTERS xp = { &Context.ExceptionRecord, &Context.ContextRecord }; + + SymInitialise(); + SCOPE_EXIT{ SymCleanup(); }; + + return GetSymbols(GetBackTrace(&xp)); } -std::vector tracer::get(const std::exception& e) +std::vector tracer::get(const EXCEPTION_POINTERS* e) { - SCOPED_ACTION(CriticalSectionLock)(m_CS); - return m_StdMap[&e]; + SymInitialise(); + SCOPE_EXIT{ SymCleanup(); }; + + return GetSymbols(GetBackTrace(e)); +} + +string tracer::get(const void* Address) +{ + SymInitialise(); + SCOPE_EXIT{ SymCleanup(); }; + + return GetSymbols(make_vector(Address)).front(); +} + +bool tracer::m_SymInitialised; + +bool tracer::SymInitialise() +{ + if (!m_SymInitialised) + { + m_SymInitialised = Imports().SymInitialize(GetCurrentProcess(), nullptr, TRUE) != FALSE; + } + return m_SymInitialised; +} + +void tracer::SymCleanup() +{ + if (m_SymInitialised) + { + m_SymInitialised = !Imports().SymCleanup(GetCurrentProcess()); + } } diff --git a/far/tracer.hpp b/far/tracer.hpp index cd0d403237..c184f8b0e5 100644 --- a/far/tracer.hpp +++ b/far/tracer.hpp @@ -41,20 +41,28 @@ class tracer: noncopyable static tracer* GetInstance(); - void store(const EXCEPTION_RECORD* Record, std::vector&& BackTrace); - void store(const std::exception& e, std::vector&& BackTrace); + void store(const std::exception& e, const EXCEPTION_POINTERS* ExceptionInfo); - std::vector get(const EXCEPTION_RECORD* Record); - std::vector get(const std::exception& e); - static std::vector GetSymbols(const std::vector& BackTrace); + static std::vector get(const std::exception& e); + static std::vector get(const EXCEPTION_POINTERS* e); + static string get(const void* Address); private: - static tracer* sTracer; + struct exception_context + { + EXCEPTION_RECORD ExceptionRecord; + CONTEXT ContextRecord; + }; + + bool get_context(const std::exception& e, exception_context& Context) const; - CriticalSection m_CS; - std::map> m_SehMap; - std::map> m_StdMap; + static bool SymInitialise(); + static void SymCleanup(); + static tracer* sTracer; + mutable CriticalSection m_CS; + std::map m_StdMap; veh_handler m_Handler; + static bool m_SymInitialised; }; diff --git a/far/vbuild.m4 b/far/vbuild.m4 index f14364a3d0..9648dd0d29 100644 --- a/far/vbuild.m4 +++ b/far/vbuild.m4 @@ -1 +1 @@ -m4_define(BUILD,4556)m4_dnl +m4_define(BUILD,4557)m4_dnl