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