-
Notifications
You must be signed in to change notification settings - Fork 221
/
Copy pathxlStackWalker.h
168 lines (141 loc) · 5.41 KB
/
xlStackWalker.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#pragma once
/***************************************************************
* This source files comes from the xLights project
* https://www.xlights.org
* https://github.com/xLightsSequencer/xLights
* See the github commit history for a record of contributing
* developers.
* Copyright claimed based on commit dates recorded in Github
* License: https://github.com/xLightsSequencer/xLights/blob/master/License.txt
**************************************************************/
#ifdef __WXMSW__
#include <wx/stackwalk.h>
#include <wx/stdpaths.h>
#include <wx/string.h>
#include <inttypes.h>
#include <iostream>
#include <fstream>
#include <libloaderapi.h>
#include <log4cpp/Category.hh>
#define USE_MAP_TO_STACKWALK
#define FORCE_MAP_TO_STACKWALK
class xlStackWalker : public wxStackWalker
{
bool LoadMapFile()
{
// dont reload it
if (_mapFileOk)
return true;
static log4cpp::Category& logger_base = log4cpp::Category::getInstance(std::string("log_base"));
wxFileName name = wxStandardPaths::Get().GetExecutablePath();
name.SetExt("map");
logger_base.debug("Loading map file " + name.GetFullPath());
HMODULE hModule = ::GetModuleHandle(nullptr);
logger_base.debug("Base module handle: 0x%016llx", (long long)hModule);
std::ifstream infile;
infile.open(name.GetFullPath().ToStdString());
long long preferedLoadAddress = 0;
if (infile.is_open()) {
logger_base.debug(" File open.");
while (!infile.eof()) {
std::string inl;
std::getline(infile, inl);
_mapLines.push_back(inl);
}
logger_base.debug(" Map file loaded.");
return true;
} else {
logger_base.debug(" File not found.");
return false;
}
}
std::string FindFunction(HMODULE hmod, void* fn)
{
wxString addr = wxString::Format("%016llx", (uint64_t)fn - (uint64_t)hmod);
wxString res;
for (const auto& it : _mapLines) {
if (it.substr(0, 16) > addr) {
return res;
}
res = it;
}
return "";
}
public:
xlStackWalker(bool const isAssert, bool const isFatalException) :
m_isAssert(isAssert)
{
if (isFatalException)
{
m_stackTrace << "Walking from an exception.\n";
WalkFromException();
}
else
{
m_stackTrace << "Regular walk.\n";
Walk();
}
}
wxString const& GetStackTrace() const { return m_stackTrace; }
virtual void OnStackFrame(wxStackFrame const& frame) override
{
m_numFrames += 1;
m_stackTrace << wxString::Format(wxT("[%02u]\t"), m_numFrames);
HMODULE hmod = 0;
::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(char*)frame.GetAddress(), &hmod);
wxString const& name = frame.GetName();
#ifdef USE_MAP_TO_STACKWALK
#ifndef FORCE_MAP_TO_STACKWALK
if (name == "")
{
#endif
if (!_mapFileOk)
_mapFileOk = LoadMapFile();
m_stackTrace << wxString::Format(wxT("ADDR:0x%016" PRIx64 "\t"), (uint64_t)frame.GetAddress());
m_stackTrace << wxString::Format(wxT("HMODULE:0x%016" PRIx64 "\t"), (uint64_t)hmod);
m_stackTrace << FindFunction(hmod, frame.GetAddress());
m_stackTrace << wxString::Format(wxT("@%llX"), frame.GetOffset());
m_stackTrace << " " << frame.GetModule() << "\n";
#ifndef FORCE_MAP_TO_STACKWALK
} else {
#endif
#endif
#ifndef FORCE_MAP_TO_STACKWALK
if (m_isAssert && name.StartsWith("wxOnAssert")) {
// Ignore all frames until the wxOnAssert() one, they are internal to wxWidgets and not interesting for the user
// (but notice that if we never find the wxOnAssert() frame, e.g. because we don't have symbol info at all, we would show
// everything which is better than not showing anything).
m_stackTrace.clear();
m_numFrames = 0;
} else {
if (name.empty()) {
m_stackTrace << wxString::Format(wxT("%p"), frame.GetAddress());
} else {
m_stackTrace << wxString::Format(wxT("%-40s"), name.c_str());
}
m_stackTrace << wxString::Format(wxT("@%llX"), frame.GetOffset());
m_stackTrace << wxT('\t') << frame.GetModule() << wxT('!') << frame.GetFileName() << wxT(':') << frame.GetLine();
for (size_t paramNum = 0; paramNum < frame.GetParamCount(); paramNum += 1) {
wxString type, name, value;
if (frame.GetParam(paramNum, &type, &name, &value)) {
m_stackTrace << wxString::Format(wxT(" (%zu: %s %s = %s)"), paramNum, type, name, value);
} else {
m_stackTrace << wxString::Format(wxT(" (%zu: ? ? = ?)"), paramNum);
}
}
m_stackTrace << wxT('\n');
}
#ifdef USE_MAP_TO_STACKWALK
}
#endif
#endif
}
private:
bool const m_isAssert = false;
wxString m_stackTrace;
unsigned m_numFrames = 0;
bool _mapFileOk = false;
std::list<std::string> _mapLines;
};
#endif