1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11350 $
6  * $Id: disassemblydlg.cpp 11350 2018-03-27 22:00:39Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/src/disassemblydlg.cpp $
8  */
9 
10 #include "sdk.h"
11 
12 #include "disassemblydlg.h"
13 #ifndef CB_PRECOMP
14     #include <wx/wxscintilla.h>
15     #include <wx/intl.h>
16     #include <wx/xrc/xmlres.h>
17     #include <wx/textctrl.h>
18     #include <wx/button.h>
19     #include <wx/listctrl.h>
20     #include <wx/wfstream.h>
21     #include <wx/fontutil.h>
22     #include <wx/stattext.h>
23     #include <wx/filedlg.h>
24 
25     #include "cbproject.h"
26     #include "configmanager.h"
27     #include "editorcolourset.h"
28     #include "editormanager.h"
29     #include "globals.h"
30     #include "manager.h"
31     #include "projectmanager.h"
32 #endif
33 
34 #include "debuggermanager.h"
35 #include "filefilters.h"
36 
37 // Keep in sync with cbEditor.cpp:
38 #define DEBUG_MARKER     6
39 #define DEBUG_STYLE      wxSCI_MARK_ARROW
40 
BEGIN_EVENT_TABLE(DisassemblyDlg,wxPanel)41 BEGIN_EVENT_TABLE(DisassemblyDlg, wxPanel)
42     EVT_BUTTON(XRCID("btnSave"), DisassemblyDlg::OnSave)
43 //    EVT_BUTTON(XRCID("btnRefresh"), DisassemblyDlg::OnRefresh)
44     EVT_CHECKBOX(XRCID("chkMode"), DisassemblyDlg::OnMixedModeCB)
45     EVT_BUTTON(XRCID("btnAdjustLine"), DisassemblyDlg::OnAdjustLine)
46 END_EVENT_TABLE()
47 
48 DisassemblyDlg::DisassemblyDlg(wxWindow* parent) :
49     m_LastActiveAddr(0),
50     m_ClearFlag(false)
51 {
52     if (!wxXmlResource::Get()->LoadPanel(this, parent, _T("dlgDisassembly")))
53         return;
54 
55     m_pCode = new wxScintilla(this, wxID_ANY, wxDefaultPosition, wxSize(1,1));
56     m_pCode->SetReadOnly(true);
57     m_pCode->SetCaretWidth(0);
58     m_pCode->SetMarginWidth(0, 0);
59     m_pCode->SetMarginType(1, wxSCI_MARGIN_SYMBOL);
60     m_pCode->SetMarginSensitive(1, 0);
61     m_pCode->SetMarginMask(1, (1 << DEBUG_MARKER));
62     m_pCode->MarkerDefine(DEBUG_MARKER, DEBUG_STYLE);
63     m_pCode->MarkerSetBackground(DEBUG_MARKER, wxColour(0xFF, 0xFF, 0x00));
64     wxXmlResource::Get()->AttachUnknownControl(_T("lcCode"), m_pCode);
65 
66     // use the same font as editor's
67     wxFont font(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
68     wxString fontstring = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/font"), wxEmptyString);
69     if (!fontstring.IsEmpty())
70     {
71         wxNativeFontInfo nfi;
72         nfi.FromString(fontstring);
73         font.SetNativeFontInfo(nfi);
74     }
75     m_pCode->StyleSetFont(wxSCI_STYLE_DEFAULT, font);
76 
77     EditorColourSet* colour_set = Manager::Get()->GetEditorManager()->GetColourSet();
78     if (colour_set)
79     {
80         HighlightLanguage lang = colour_set->GetHighlightLanguage(wxSCI_LEX_ASM);
81         colour_set->Apply(lang, (cbStyledTextCtrl*)m_pCode, false, true);
82     }
83 
84     m_MixedModeCB = (wxCheckBox*)FindWindow(XRCID("chkMode"));
85     m_MixedModeCB->SetValue(Manager::Get()->GetDebuggerManager()->IsDisassemblyMixedMode());
86 
87     cbStackFrame sf;
88     Clear(sf);
89 }
90 
Clear(const cbStackFrame & frame)91 void DisassemblyDlg::Clear(const cbStackFrame& frame)
92 {
93     m_FrameFunction = frame.IsValid() ? frame.GetSymbol() : _T("??");
94     m_FrameAddress = _T("??");
95     if (frame.IsValid())
96         m_FrameAddress = frame.GetAddressAsString();
97 
98     m_LineTypes.clear();
99 
100     XRCCTRL(*this, "lblFunction", wxStaticText)->SetLabel(m_FrameFunction);
101     XRCCTRL(*this, "lblAddress", wxStaticText)->SetLabel(m_FrameAddress);
102 
103     m_HasActiveAddr = false;
104 
105     m_pCode->SetReadOnly(false);
106 
107     cbDebuggerPlugin *plugin = Manager::Get()->GetDebuggerManager()->GetActiveDebugger();
108 
109     if (frame.IsValid() && plugin->IsRunning())
110     {
111         // if debugger is running, show a message
112         m_pCode->SetText(_("\"Please wait while disassembling...\""));
113         m_ClearFlag = true; // clear the above message when adding the first line
114     }
115     else
116     {
117         // if debugger isn't running, just clear the window
118         m_pCode->ClearAll();
119         m_ClearFlag = false;
120     }
121     m_pCode->SetReadOnly(true);
122     m_pCode->MarkerDeleteAll(DEBUG_MARKER);
123 }
124 
AddAssemblerLine(uint64_t addr,const wxString & line)125 void DisassemblyDlg::AddAssemblerLine(uint64_t addr, const wxString& line)
126 {
127     m_pCode->SetReadOnly(false);
128     if (m_ClearFlag)
129     {
130         m_ClearFlag = false;
131         m_pCode->ClearAll();
132     }
133 
134     m_pCode->AppendText(cbDebuggerAddressToString(addr) + wxT("\t") + line + wxT("\n"));
135     SetActiveAddress(m_LastActiveAddr);
136     m_pCode->SetReadOnly(true);
137     m_LineTypes.push_back('D') ;
138 }
139 
AddSourceLine(int lineno,const wxString & line)140 void DisassemblyDlg::AddSourceLine(int lineno, const wxString& line)
141 {
142     m_pCode->SetReadOnly(false);
143     if (m_ClearFlag)
144     {
145         m_ClearFlag = false;
146         m_pCode->ClearAll();
147     }
148     wxString fmt;
149     fmt.Printf(_T(";%-3d:\t%s\n"), lineno, line.c_str());
150 
151     m_pCode->AppendText(fmt);
152 
153     m_pCode->SetReadOnly(true);
154     m_LineTypes.push_back('S') ;
155 }
156 
CenterLine(int lineno)157 void DisassemblyDlg::CenterLine(int lineno)
158 {
159     //make line middle of display window if reasonable
160     int firstdispline ;
161     int los = m_pCode->LinesOnScreen() ;
162     if (lineno > los / 2)
163         firstdispline = lineno - (los/2) ;
164     else
165         firstdispline = 0 ; //or is it zero?
166     m_pCode->SetFirstVisibleLine(firstdispline) ;
167 }
168 
CenterCurrentLine()169 void DisassemblyDlg::CenterCurrentLine()
170 {
171     int displine;
172     displine = m_pCode->GetCurrentLine() ;
173     CenterLine(displine);
174 }
175 
SetActiveAddress(uint64_t addr)176 bool DisassemblyDlg::SetActiveAddress(uint64_t addr)
177 {
178     if (m_HasActiveAddr && addr == m_LastActiveAddr)
179         return m_HasActiveAddr ;
180     m_HasActiveAddr = false;
181     m_LastActiveAddr = addr;
182     bool MixedAsmMode = Manager::Get()->GetDebuggerManager()->IsDisassemblyMixedMode();
183     for (int i = 0; i < m_pCode->GetLineCount() && i < int(m_LineTypes.size()); ++i)
184     {
185         if(MixedAsmMode && m_LineTypes[i] == 'S')
186             continue;
187 
188         const wxString &str = m_pCode->GetLine(i).AfterFirst(_T('x')).BeforeFirst(_T('\t'));
189         uint64_t lineaddr = cbDebuggerStringToAddress(str);
190         if (lineaddr > 0 && (lineaddr == addr))
191         {
192             m_pCode->MarkerDeleteAll(DEBUG_MARKER);
193             m_pCode->MarkerAdd(i, DEBUG_MARKER);
194             m_pCode->GotoLine(i);
195 
196             //check and shift window lines if needed
197             if (!m_pCode->GetLineVisible(i))
198             {
199                 this->CenterLine(i);
200             }
201             //are we close to bottom line? if so shift display if possible
202             else if (i == (m_pCode->LinesOnScreen() + m_pCode->GetFirstVisibleLine() - 1))
203             {
204                 this->CenterLine(i);
205             }
206 
207             m_HasActiveAddr = true;
208             break;
209         }
210     }
211     return m_HasActiveAddr ;
212 }
213 
OnAdjustLine(cb_unused wxCommandEvent & event)214 void DisassemblyDlg::OnAdjustLine(cb_unused wxCommandEvent& event)
215 {
216     int los = m_pCode->LinesOnScreen();
217 
218     int displine;
219     if (m_pCode->GetCurrentLine() == m_pCode->GetFirstVisibleLine())
220         displine = m_pCode->GetCurrentLine();
221     else if (m_pCode->GetCurrentLine() == m_pCode->GetFirstVisibleLine() + los/2)
222         displine = m_pCode->GetCurrentLine() - (los/2) + 1;
223     else
224         displine = m_pCode->GetCurrentLine() + (los/2);
225 
226     if (displine < 0)
227         displine = 0;
228     CenterLine(displine);
229 }
230 
OnSave(cb_unused wxCommandEvent & event)231 void DisassemblyDlg::OnSave(cb_unused wxCommandEvent& event)
232 {
233     wxFileDialog dlg(this,
234                      _("Save as text file"),
235                      _T("assembly_dump.txt"),
236                      wxEmptyString,
237                      FileFilters::GetFilterAll(),
238                      wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
239     PlaceWindow(&dlg);
240     if (dlg.ShowModal() != wxID_OK)
241         return;
242 
243     wxString output;
244     cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
245     if (prj)
246     {
247         output << _("Project title : ") << prj->GetTitle() << _T('\n');
248         output << _("Project path  : ") << prj->GetBasePath() << _T('\n') << _T('\n');
249     }
250 
251     output << _("Frame function: ") << m_FrameFunction << _T('\n');
252     output << _("Frame address : ") << m_FrameAddress << _T('\n');
253     output << wxString(_T('-'), 80) << _T('\n');
254     output << m_pCode->GetText();
255 
256     if (!cbSaveToFile(dlg.GetPath(), output))
257         cbMessageBox(_("Could not save file..."), _("Error"), wxICON_ERROR);
258 }
259 
OnRefresh(cb_unused wxCommandEvent & event)260 void DisassemblyDlg::OnRefresh(cb_unused wxCommandEvent& event)
261 {
262     cbDebuggerPlugin *plugin = Manager::Get()->GetDebuggerManager()->GetActiveDebugger();
263     cbAssert(plugin);
264     plugin->RequestUpdate(cbDebuggerPlugin::Disassembly);
265 }
266 
OnMixedModeCB(cb_unused wxCommandEvent & event)267 void DisassemblyDlg::OnMixedModeCB(cb_unused wxCommandEvent &event)
268 {
269     DebuggerManager &manager = *Manager::Get()->GetDebuggerManager();
270     bool newMode = !manager.IsDisassemblyMixedMode();
271     manager.SetDisassemblyMixedMode(newMode);
272     m_MixedModeCB->SetValue(newMode);
273 
274     cbDebuggerPlugin *plugin = manager.GetActiveDebugger();
275     cbAssert(plugin);
276     plugin->RequestUpdate(cbDebuggerPlugin::Disassembly);
277 }
278 
EnableWindow(bool enable)279 void DisassemblyDlg::EnableWindow(bool enable)
280 {
281     Enable(enable);
282 }
283