1
#include "Addr2LineUIMain.h"
3
//(*InternalHeaders(Addr2LineUIDialog)
4
#include <wx/settings.h>
10
#include <wx/busyinfo.h>
11
#include <wx/msgdlg.h>
13
#include <wx/textfile.h>
14
#include <wx/utils.h> // wxExecute
16
//(*IdInit(Addr2LineUIDialog)
17
const long Addr2LineUIDialog::ID_CRASH_LOG = wxNewId();
18
const long Addr2LineUIDialog::ID_ADDR2LINE = wxNewId();
19
const long Addr2LineUIDialog::ID_DIR_PREPEND = wxNewId();
20
const long Addr2LineUIDialog::ID_CHK_REPLACE = wxNewId();
21
const long Addr2LineUIDialog::ID_TXT_REPLACE_THIS = wxNewId();
22
const long Addr2LineUIDialog::ID_LBL_REPLACE = wxNewId();
23
const long Addr2LineUIDialog::ID_TXT_REPLACE_THAT = wxNewId();
24
const long Addr2LineUIDialog::ID_CHK_SKIP_UNRESOLVABLE = wxNewId();
25
const long Addr2LineUIDialog::ID_TXT_CRASH_LOG_CONTENT = wxNewId();
26
const long Addr2LineUIDialog::ID_TXT_RESULT = wxNewId();
27
const long Addr2LineUIDialog::ID_BTN_OPERATE = wxNewId();
28
const long Addr2LineUIDialog::ID_BTN_QUIT = wxNewId();
31
BEGIN_EVENT_TABLE(Addr2LineUIDialog,wxDialog)
32
//(*EventTable(Addr2LineUIDialog)
36
Addr2LineUIDialog::Addr2LineUIDialog(wxWindow* parent) :
39
mCrashLogFileContent(),
40
mAddr2Line(wxT("addr2line")),
43
//(*Initialize(Addr2LineUIDialog)
44
wxStaticText* lblDirPrepend;
45
wxBoxSizer* bszAddr2Line;
48
wxStaticText* lblCrashLog;
49
wxBoxSizer* bszReplace;
51
wxStaticText* lblAddr2Line;
52
wxStaticLine* stlLine;
54
Create(parent, wxID_ANY, _("Addr2LineUI"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX, _T("wxID_ANY"));
55
bszMainH = new wxBoxSizer(wxHORIZONTAL);
56
bszMainV = new wxBoxSizer(wxVERTICAL);
57
bszAddr2Line = new wxBoxSizer(wxVERTICAL);
58
lblCrashLog = new wxStaticText(this, wxID_ANY, _("Select crash log file:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
59
bszAddr2Line->Add(lblCrashLog, 0, wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
60
m_FPCrashLog = new wxFilePickerCtrl(this, ID_CRASH_LOG, wxEmptyString, _("Select crash log"), _T("Report files (*.rpt)|*.rpt|Log files (*.log)|*.log|All files (*.*)|*.*"), wxDefaultPosition, wxDefaultSize, wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_USE_TEXTCTRL, wxDefaultValidator, _T("ID_CRASH_LOG"));
61
bszAddr2Line->Add(m_FPCrashLog, 0, wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
62
lblAddr2Line = new wxStaticText(this, wxID_ANY, _("Select Addr2Line tool:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
63
bszAddr2Line->Add(lblAddr2Line, 0, wxTOP|wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
64
m_FPAddr2Line = new wxFilePickerCtrl(this, ID_ADDR2LINE, wxEmptyString, _("Select addr2line tool"), _T("Executables (*.exe)|*.exe|All files (*.*)|*.*"), wxDefaultPosition, wxDefaultSize, wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_USE_TEXTCTRL, wxDefaultValidator, _T("ID_ADDR2LINE"));
65
bszAddr2Line->Add(m_FPAddr2Line, 0, wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
66
lblDirPrepend = new wxStaticText(this, wxID_ANY, _("(Optionally) Select directory to prepend:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
67
bszAddr2Line->Add(lblDirPrepend, 0, wxTOP|wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
68
m_DPDirPrepend = new wxDirPickerCtrl(this, ID_DIR_PREPEND, wxEmptyString, _("Select directory to prepend"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST|wxDIRP_USE_TEXTCTRL, wxDefaultValidator, _T("ID_DIR_PREPEND"));
69
bszAddr2Line->Add(m_DPDirPrepend, 0, wxEXPAND|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
70
bszMainV->Add(bszAddr2Line, 0, wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
71
bszReplace = new wxBoxSizer(wxHORIZONTAL);
72
chkReplace = new wxCheckBox(this, ID_CHK_REPLACE, _("Replace:"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_CHK_REPLACE"));
73
chkReplace->SetValue(false);
74
bszReplace->Add(chkReplace, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
75
txtReplaceThis = new wxTextCtrl(this, ID_TXT_REPLACE_THIS, _("this"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TXT_REPLACE_THIS"));
76
txtReplaceThis->Disable();
77
bszReplace->Add(txtReplaceThis, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
78
lblReplace = new wxStaticText(this, ID_LBL_REPLACE, _("...with:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_LBL_REPLACE"));
79
lblReplace->Disable();
80
bszReplace->Add(lblReplace, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
81
txtReplaceThat = new wxTextCtrl(this, ID_TXT_REPLACE_THAT, _("that"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TXT_REPLACE_THAT"));
82
txtReplaceThat->Disable();
83
bszReplace->Add(txtReplaceThat, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
84
chkSkipUnresolvable = new wxCheckBox(this, ID_CHK_SKIP_UNRESOLVABLE, _("Skip unresolvable"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_CHK_SKIP_UNRESOLVABLE"));
85
chkSkipUnresolvable->SetValue(false);
86
bszReplace->Add(chkSkipUnresolvable, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
87
bszMainV->Add(bszReplace, 0, wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
88
txtCrashLogContent = new wxTextCtrl(this, ID_TXT_CRASH_LOG_CONTENT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE, wxDefaultValidator, _T("ID_TXT_CRASH_LOG_CONTENT"));
89
txtCrashLogContent->SetMinSize(wxSize(450,200));
90
wxFont txtCrashLogContentFont = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT);
91
if ( !txtCrashLogContentFont.Ok() ) txtCrashLogContentFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
92
txtCrashLogContent->SetFont(txtCrashLogContentFont);
93
bszMainV->Add(txtCrashLogContent, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
94
txtResult = new wxTextCtrl(this, ID_TXT_RESULT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE, wxDefaultValidator, _T("ID_TXT_RESULT"));
95
txtResult->SetMinSize(wxSize(450,200));
96
wxFont txtResultFont = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT);
97
if ( !txtResultFont.Ok() ) txtResultFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
98
txtResult->SetFont(txtResultFont);
99
bszMainV->Add(txtResult, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
100
stlLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxSize(10,-1), wxLI_HORIZONTAL, _T("wxID_ANY"));
101
bszMainV->Add(stlLine, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP, 5);
102
btnOperate = new wxButton(this, ID_BTN_OPERATE, _("Operate"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_OPERATE"));
103
btnOperate->Disable();
104
bszMainV->Add(btnOperate, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
105
btnQuit = new wxButton(this, ID_BTN_QUIT, _("Quit"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BTN_QUIT"));
106
bszMainV->Add(btnQuit, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
107
bszMainH->Add(bszMainV, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4);
110
bszMainH->SetSizeHints(this);
112
Connect(ID_CRASH_LOG,wxEVT_COMMAND_FILEPICKER_CHANGED,wxFileDirPickerEventHandler(Addr2LineUIDialog::OnCrashLogFile));
113
Connect(ID_ADDR2LINE,wxEVT_COMMAND_FILEPICKER_CHANGED,wxFileDirPickerEventHandler(Addr2LineUIDialog::OnAddr2LineFile));
114
Connect(ID_DIR_PREPEND,wxEVT_COMMAND_DIRPICKER_CHANGED,wxFileDirPickerEventHandler(Addr2LineUIDialog::OnDirPrependDir));
115
Connect(ID_CHK_REPLACE,wxEVT_COMMAND_CHECKBOX_CLICKED,wxCommandEventHandler(Addr2LineUIDialog::OnReplaceClick));
116
Connect(ID_BTN_OPERATE,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(Addr2LineUIDialog::OnOperateClick));
117
Connect(ID_BTN_QUIT,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(Addr2LineUIDialog::OnQuit));
120
mFileConfig.Read(wxT("CrashLog"), &mCrashLog, wxT("")); m_FPCrashLog->SetPath(mCrashLog);
121
mFileConfig.Read(wxT("Addr2Line"), &mAddr2Line, wxT("")); m_FPAddr2Line->SetPath(mAddr2Line);
122
mFileConfig.Read(wxT("DirPrepend"), &mDirPrepend, wxT("")); m_DPDirPrepend->SetPath(mDirPrepend);
124
bool Replace; mFileConfig.Read(wxT("Replace"), &Replace, false ); chkReplace->SetValue(Replace);
125
if (Replace) { txtReplaceThis->Enable(); lblReplace->Enable(); txtReplaceThat->Enable(); }
126
wxString ReplaceThis; mFileConfig.Read(wxT("ReplaceThis"), &ReplaceThis, wxT("")); txtReplaceThis->SetValue(ReplaceThis);
127
wxString ReplaceThat; mFileConfig.Read(wxT("ReplaceThat"), &ReplaceThat, wxT("")); txtReplaceThat->SetValue(ReplaceThat);
129
bool SkipUnresolvable; mFileConfig.Read(wxT("SkipUnresolvable"), &SkipUnresolvable, false ); chkSkipUnresolvable->SetValue(SkipUnresolvable);
132
Addr2LineUIDialog::~Addr2LineUIDialog()
134
//(*Destroy(Addr2LineUIDialog)
138
void Addr2LineUIDialog::OnCrashLogFile(wxFileDirPickerEvent& event)
140
mCrashLog = event.GetPath();
142
wxTextFile file(mCrashLog);
145
mCrashLogFileContent.Clear();
146
txtCrashLogContent->Clear();
147
for (wxString line = file.GetFirstLine(); !file.Eof(); line = file.GetNextLine())
149
mCrashLogFileContent.Add(line);
150
txtCrashLogContent->AppendText(line + wxT("\n"));
153
if (mCrashLogFileContent.Count()>0) btnOperate->Enable(); else btnOperate->Disable();
156
wxMessageBox(wxT("Error: File could not be opened."), wxT("Addr2LineUI"), wxOK|wxICON_ERROR, this);
159
void Addr2LineUIDialog::OnAddr2LineFile(wxFileDirPickerEvent& event)
161
mAddr2Line = event.GetPath();
164
void Addr2LineUIDialog::OnDirPrependDir(wxFileDirPickerEvent& event)
166
mDirPrepend = event.GetPath();
169
void Addr2LineUIDialog::OnReplaceClick(wxCommandEvent& event)
171
if (event.IsChecked())
172
{ txtReplaceThis->Enable(); lblReplace->Enable(); txtReplaceThat->Enable(); }
174
{ txtReplaceThis->Disable(); lblReplace->Disable(); txtReplaceThat->Disable(); }
177
void Addr2LineUIDialog::OnOperateClick(wxCommandEvent& WXUNUSED(event))
179
// Style w/ debug symbols:
181
004013AE 00000008 60000000 40166666 sample_d.exe!Function [C:\Devel\CodeBlocks\MinGW\bin\DrMinGW\demo/sample.cpp @ 10]
184
static void Function(int i, double j, const char * pszString) {
185
> sscanf("12345", "%i", (int *)1);
190
00401CCE 00000004 40B33333 0028FF08 sample_d.exe!StaticMethod [C:\Devel\CodeBlocks\MinGW\bin\DrMinGW\demo/sample.cpp @ 15]
193
static void StaticMethod(int i, float j) {
194
> Function(i * 2, j, "Hello");
200
// Sytle w/o debug symbols:
202
004013AE 00000008 60000000 40166666 sample_r.exe!Function(int, double, char const*)
203
00401CCE 00000004 40B33333 0028FF08 sample_r.exe!Class::StaticMethod(int, float)
206
// The address element "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX " needs to be removed later, compute size here.
207
wxRegEx reAddr32(wxT("([A-Fa-f0-9]{8})")); wxString tag32(wxT("AddrPC Params")); size_t len32 = 4*8 +4; // 4 times 8bit address + 4 times space
208
wxRegEx reAddr64(wxT("([A-Fa-f0-9]{16})")); wxString tag64(wxT("AddrPC Params")); size_t len64 = 4*16+4; // 4 times 16bit address + 4 times space
209
bool is64Bit = false;
212
txtResult->AppendText(wxT("Working directory is '") + wxGetCwd() + wxT("'.\n"));
215
bool operate_line = false;
216
for (size_t i=0; i<mCrashLogFileContent.Count(); i++)
218
wxString line = mCrashLogFileContent.Item(i);
219
if (line.IsSameAs(tag32))
221
txtResult->AppendText(wxT("*************************************\n"));
222
txtResult->AppendText(wxT("* Found (another) 32 bit call stack *\n"));
223
txtResult->AppendText(wxT("*************************************\n"));
227
else if (line.IsSameAs(tag64))
229
txtResult->AppendText(wxT("*************************************\n"));
230
txtResult->AppendText(wxT("* Found (another) 64 bit call stack *\n"));
231
txtResult->AppendText(wxT("*************************************\n"));
240
line = line.Trim(true).Trim(false);
244
if (!is64Bit && !reAddr32.Matches(line) )
246
if ( is64Bit && !reAddr64.Matches(line) )
256
for (size_t j=1; j<=reAddr64.GetMatchCount(); j++)
260
case 1: { theAddr = reAddr64.GetMatch(line, 1); } break;
261
case 2: // fall through
262
case 3: // fall through
263
case 4: // fall through
270
for (size_t j=1; j<=reAddr32.GetMatchCount(); j++)
274
case 1: { theAddr = reAddr32.GetMatch(line, 1); } break;
275
case 2: // fall through
276
case 3: // fall through
277
case 4: // fall through
284
if (theAddr.IsEmpty())
286
txtResult->AppendText(wxT("Skipping empty address '") + line + wxT("'\n"));
290
// Remove "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX "
291
line = line.Right(line.Length() - (is64Bit ? len64 : len32)).Trim(true).Trim(false) ; // 8 times address + 8 times space
292
wxString sep = wxT("!");
293
int sep_pos = line.Find(wxT('!'), true);
294
if (sep_pos!=wxNOT_FOUND)
295
theFile = line.SubString(0,sep_pos-1);
298
if (theFile.IsEmpty())
300
txtResult->AppendText(wxT("Skipping address '") + theAddr + wxT("' for unknown file : '") + theFile + wxT("'\n"));
304
// prepend directory if requested
305
if (!mDirPrepend.IsEmpty())
306
theFile = mDirPrepend + wxFILE_SEP_PATH + theFile;
308
// replacements in command (if any):
309
if (chkReplace->IsChecked())
311
wxString repl_this = txtReplaceThis->GetValue();
312
wxString repl_that = txtReplaceThat->GetValue();
313
// avoid endless loops
314
if ( !repl_this.IsSameAs(repl_that)
315
&& !( repl_this.Trim(true).Trim(false).IsEmpty()
316
&& repl_that.Trim(true).Trim(false).IsEmpty() )
317
&& !(repl_this.Trim(true).Trim(false).IsSameAs(
318
repl_that.Trim(true).Trim(false)) ) )
320
theFile.Replace(repl_this, repl_that);
324
wxMessageBox(wxT("Error: Invalid setup for replacements (would cause a loop)."), wxT("Addr2LineUI"), wxOK|wxICON_ERROR, this);
325
chkReplace->SetValue(false);
329
if ( !wxFileExists(theFile) )
331
txtResult->AppendText(wxT("Skipping non-existent file '") + theFile + wxT("'\n"));
335
// apply file mask if needed
336
if (theFile.Contains(wxT(" "))) theFile = wxT("\"") + theFile + wxT("\"");
338
// compute (initial) command line argument to addr2line
339
wxString command_args = wxT(" -C -e ") + theFile + wxT(" ") + theAddr;
340
// Now prepend the addr2line tool and compile the full command
341
wxString command = mAddr2Line + command_args;
343
{ // BEGIN Lifetime of wxWindowDisabler and wxBusyInfo
344
wxWindowDisabler disableAll;
345
wxBusyInfo wait(wxT("Please wait, operating:\n") + command);
347
wxArrayString output, error;
348
long ret = wxExecute(command, output, error); // sync process
351
txtResult->AppendText(command + wxT(":\n"));
352
txtResult->AppendText(wxT("-1 for: ") + command + wxT("\n"));
353
txtResult->AppendText(wxT("----------------------------------------\n"));
355
else if (!error.IsEmpty())
357
txtResult->AppendText(command + wxT(":\n"));
358
txtResult->AppendText(wxT("Error for: ") + command + wxT("\n:"));
359
for (size_t j=0; j<error.Count(); j++)
360
txtResult->AppendText(error.Item(j) + wxT("\n"));
361
txtResult->AppendText(wxT("----------------------------------------\n"));
366
if (chkSkipUnresolvable->IsChecked())
368
if (output.Count()>0 && output.Item(0).Contains(wxT("??:0")))
374
txtResult->AppendText(command + wxT(":\n"));
375
txtResult->AppendText(theFile + wxT("[") + theAddr + wxT("]:\n"));
376
for (size_t j=0; j<output.Count(); j++)
377
txtResult->AppendText(output.Item(j) + wxT("\n"));
378
txtResult->AppendText(wxT("----------------------------------------\n"));
381
}// END Lifetime of wxWindowDisabler and wxBusyInfo
385
void Addr2LineUIDialog::OnQuit(wxCommandEvent& WXUNUSED(event))
387
mFileConfig.Write(wxT("CrashLog"), mCrashLog );
388
mFileConfig.Write(wxT("Addr2Line"), mAddr2Line );
389
mFileConfig.Write(wxT("DirPrepend"), mDirPrepend );
390
mFileConfig.Write(wxT("Replace"), chkReplace->IsChecked() );
391
mFileConfig.Write(wxT("ReplaceThis"), txtReplaceThis->GetValue() );
392
mFileConfig.Write(wxT("ReplaceThat"), txtReplaceThat->GetValue() );
393
mFileConfig.Write(wxT("SkipUnresolvable"), chkSkipUnresolvable->IsChecked());