1
|
#include "Debuggers.h"
|
2
|
|
3
|
#ifdef COMPILER_MSC
|
4
|
|
5
|
#pragma comment(lib, "DbgHelp.lib")
|
6
|
#pragma comment(lib, "psapi.lib")
|
7
|
|
8
|
#define LLOG(x)
|
9
|
|
10
|
#define KEYGROUPNAME "PdbDebugger"
|
11
|
#define KEYNAMESPACE PdbKeys
|
12
|
#define KEYFILE <ide/Debuggers/Pdb.key>
|
13
|
#include <CtrlLib/key_source.h>
|
14
|
|
15
|
using namespace PdbKeys;
|
16
|
|
17
|
void Pdb::DebugBar(Bar& bar)
|
18
|
{
|
19
|
bar.Add(AK_STOP, DbgImg::StopDebug(), THISBACK(Stop));
|
20
|
bool b = !IdeIsDebugLock();
|
21
|
bar.Separator();
|
22
|
bar.Add(b, AK_STEPINTO, DbgImg::StepInto(), THISBACK1(Trace, false));
|
23
|
bar.Add(b, AK_STEPOVER, DbgImg::StepOver(), THISBACK1(Trace, true));
|
24
|
bar.Add(b, AK_STEPOUT, DbgImg::StepOut(), THISBACK(StepOut));
|
25
|
bar.Add(b, AK_RUNTO, DbgImg::RunTo(), THISBACK(DoRunTo));
|
26
|
bar.Add(b, AK_RUN, DbgImg::Run(), THISBACK(Run));
|
27
|
bar.Add(b, AK_SETIP, DbgImg::SetIp(), THISBACK(SetIp));
|
28
|
bar.Add(!b, AK_STOP, DbgImg::Stop(), THISBACK(BreakRunning));
|
29
|
bar.MenuSeparator();
|
30
|
bar.Add(b, AK_AUTOS, THISBACK1(SetTab, 0));
|
31
|
bar.Add(b, AK_LOCALS, THISBACK1(SetTab, 1));
|
32
|
bar.Add(b, AK_WATCHES, THISBACK1(SetTab, 2));
|
33
|
bar.Add(b, AK_CLEARWATCHES, THISBACK(ClearWatches));
|
34
|
bar.Add(b, AK_ADDWATCH, THISBACK(AddWatch));
|
35
|
bar.Add(b, AK_EXPLORER, THISBACK(DoExplorer));
|
36
|
bar.Add(b, AK_MEMORY, THISBACK1(SetTab, 4));
|
37
|
bar.MenuSeparator();
|
38
|
bar.Add(b, "Copy backtrace", THISBACK(CopyStack));
|
39
|
bar.Add(b, "Copy dissassembly", THISBACK(CopyDisas));
|
40
|
}
|
41
|
|
42
|
void Pdb::Tab()
|
43
|
{
|
44
|
switch(tab.Get()) {
|
45
|
case 0: autos.SetFocus(); break;
|
46
|
case 1: locals.SetFocus(); break;
|
47
|
case 2: watches.SetFocus(); break;
|
48
|
case 3: explorer.SetFocus(); break;
|
49
|
case 4: memory.SetFocus(); break;
|
50
|
}
|
51
|
Data();
|
52
|
}
|
53
|
|
54
|
bool Pdb::Key(dword key, int count)
|
55
|
{
|
56
|
if(key >= 32 && key < 65535 && tab.Get() == 2) {
|
57
|
watches.DoInsertAfter();
|
58
|
Ctrl* f = GetFocusCtrl();
|
59
|
if(f && watches.HasChildDeep(f))
|
60
|
f->Key(key, count);
|
61
|
return true;
|
62
|
}
|
63
|
if(key == K_ENTER && expexp.HasFocus()) {
|
64
|
Explore(~expexp);
|
65
|
return true;
|
66
|
}
|
67
|
return Ctrl::Key(key, count);
|
68
|
}
|
69
|
|
70
|
#define CONFIGNAME "pdb debugger"
|
71
|
|
72
|
void Pdb::Serialize(Stream& s)
|
73
|
{
|
74
|
int version = 0;
|
75
|
s / version;
|
76
|
memory.SerializeSettings(s);
|
77
|
s % split;
|
78
|
}
|
79
|
|
80
|
INITBLOCK
|
81
|
{
|
82
|
RegisterGlobalConfig(CONFIGNAME);
|
83
|
}
|
84
|
|
85
|
bool Pdb::Create(One<Host> local, const String& exefile, const String& cmdline)
|
86
|
{
|
87
|
STARTUPINFO si;
|
88
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
89
|
si.cb = sizeof(STARTUPINFO);
|
90
|
si.dwFlags = 0;
|
91
|
String cl;
|
92
|
if(exefile.Find(' ') >= 0)
|
93
|
cl << '\"' << exefile << '\"';
|
94
|
else
|
95
|
cl << exefile;
|
96
|
if(!IsNull(cmdline))
|
97
|
cl << ' ' << cmdline;
|
98
|
|
99
|
Buffer<char> cmd(cl.GetLength() + 1);
|
100
|
memcpy(cmd, cl, cl.GetLength() + 1);
|
101
|
PROCESS_INFORMATION pi;
|
102
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
103
|
Buffer<char> env(local->GetEnvironment().GetCount() + 1);
|
104
|
memcpy(env, ~local->GetEnvironment(), local->GetEnvironment().GetCount() + 1);
|
105
|
bool h = CreateProcess(exefile, cmd, NULL, NULL, TRUE,
|
106
|
NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE|DEBUG_ONLY_THIS_PROCESS|DEBUG_PROCESS,
|
107
|
~env, NULL, &si, &pi);
|
108
|
if(!h) {
|
109
|
Exclamation("Error creating process&[* " + DeQtf(exefile) + "]&" +
|
110
|
"Windows error: " + DeQtf(GetLastErrorMessage()));
|
111
|
return false;
|
112
|
}
|
113
|
hProcess = pi.hProcess;
|
114
|
CloseHandle(pi.hThread);
|
115
|
|
116
|
IdeSetBottom(*this);
|
117
|
IdeSetRight(disas);
|
118
|
|
119
|
LoadFromGlobal(*this, CONFIGNAME);
|
120
|
|
121
|
if(!SymInitialize(hProcess, 0, FALSE)) {
|
122
|
Error();
|
123
|
return false;
|
124
|
}
|
125
|
SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_UNDNAME|SYMOPT_NO_UNQUALIFIED_LOADS);
|
126
|
|
127
|
lock = 0;
|
128
|
stop = false;
|
129
|
refreshmodules = true;
|
130
|
terminated = false;
|
131
|
|
132
|
running = true;
|
133
|
|
134
|
RunToException();
|
135
|
|
136
|
|
137
|
return true;
|
138
|
}
|
139
|
|
140
|
INITBLOCK {
|
141
|
RegisterWorkspaceConfig("pdb-debugger");
|
142
|
}
|
143
|
|
144
|
void Pdb::SerializeSession(Stream& s)
|
145
|
{
|
146
|
int version = 0;
|
147
|
s / version;
|
148
|
int n = watches.GetCount();
|
149
|
s / n;
|
150
|
for(int i = 0; i < n; i++) {
|
151
|
String w;
|
152
|
if(s.IsStoring())
|
153
|
w = watches.Get(i, 0);
|
154
|
s % w;
|
155
|
if(s.IsLoading())
|
156
|
watches.Add(w);
|
157
|
}
|
158
|
}
|
159
|
|
160
|
Pdb::Pdb()
|
161
|
{
|
162
|
hProcess = INVALID_HANDLE_VALUE;
|
163
|
|
164
|
CtrlLayout(regs);
|
165
|
regs.Height(regs.GetLayoutSize().cy);
|
166
|
AddReg("eax", ®s.eax);
|
167
|
AddReg("ebx", ®s.ebx);
|
168
|
AddReg("ecx", ®s.ecx);
|
169
|
AddReg("edx", ®s.edx);
|
170
|
AddReg("esi", ®s.esi);
|
171
|
AddReg("edi", ®s.edi);
|
172
|
AddReg("ebp", ®s.ebp);
|
173
|
AddReg("esp", ®s.esp);
|
174
|
regs.Color(SColorLtFace);
|
175
|
regs.AddFrame(TopSeparatorFrame());
|
176
|
regs.AddFrame(RightSeparatorFrame());
|
177
|
|
178
|
locals.NoHeader();
|
179
|
locals.AddColumn("", 1);
|
180
|
locals.AddColumn("", 6).SetDisplay(Single<VisualDisplay>());
|
181
|
locals.WhenEnterRow = THISBACK1(SetTreeA, &locals);
|
182
|
locals.WhenBar = THISBACK(LocalsMenu);
|
183
|
locals.WhenLeftDouble = THISBACK1(ExploreKey, &locals);
|
184
|
|
185
|
watches.NoHeader();
|
186
|
watches.AddColumn("", 1).Edit(watchedit);
|
187
|
watches.AddColumn("", 6).SetDisplay(Single<VisualDisplay>());
|
188
|
watches.Inserting().Removing();
|
189
|
watches.WhenEnterRow = THISBACK1(SetTreeA, &watches);
|
190
|
watches.WhenBar = THISBACK(WatchesMenu);
|
191
|
watches.WhenLeftDouble = THISBACK1(ExploreKey, &watches);
|
192
|
|
193
|
autos.NoHeader();
|
194
|
autos.AddColumn("", 1);
|
195
|
autos.AddColumn("", 6).SetDisplay(Single<VisualDisplay>());
|
196
|
autos.WhenEnterRow = THISBACK1(SetTreeA, &autos);
|
197
|
autos.WhenBar = THISBACK(AutosMenu);
|
198
|
autos.WhenLeftDouble = THISBACK1(ExploreKey, &autos);
|
199
|
|
200
|
int c = EditField::GetStdHeight();
|
201
|
explorer.AddColumn("", 1);
|
202
|
explorer.AddColumn("", 6).SetDisplay(Single<VisualDisplay>());
|
203
|
explorer_pane.Add(exback.LeftPos(0, c).TopPos(0, c));
|
204
|
explorer_pane.Add(exfw.LeftPos(c + 2, c).TopPos(0, c));
|
205
|
explorer_pane.Add(expexp.HSizePos(2 * c + 4).TopPos(0, c));
|
206
|
explorer_pane.Add(explorer.HSizePos().VSizePos(EditField::GetStdHeight(), 0));
|
207
|
explorer.NoHeader();
|
208
|
explorer.WhenEnterRow = THISBACK(ExplorerTree);
|
209
|
explorer.WhenLeftDouble = THISBACK(ExpExp);
|
210
|
explorer.WhenBar = THISBACK(ExplorerMenu);
|
211
|
|
212
|
exback.SetImage(DbgImg::ExplorerBack());
|
213
|
exback <<= THISBACK(ExBack);
|
214
|
exfw.SetImage(DbgImg::ExplorerFw());
|
215
|
exfw <<= THISBACK(ExFw);
|
216
|
exback.Disable();
|
217
|
exfw.Disable();
|
218
|
|
219
|
tab.Add(autos.SizePos(), "Autos");
|
220
|
tab.Add(locals.SizePos(), "Locals");
|
221
|
tab.Add(watches.SizePos(), "Watches");
|
222
|
tab.Add(explorer_pane.SizePos(), "Explorer");
|
223
|
memory.cdb = this;
|
224
|
tab.Add(memory.SizePos(), "Memory");
|
225
|
|
226
|
dlock = " Running..";
|
227
|
dlock.SetFrame(BlackFrame());
|
228
|
dlock.SetInk(Red);
|
229
|
dlock.NoTransparent();
|
230
|
dlock.Hide();
|
231
|
framelist.Ctrl::Add(dlock.SizePos());
|
232
|
|
233
|
pane.Add(tab.SizePos());
|
234
|
pane.Add(threadlist.LeftPosZ(320, 60).TopPos(2, EditField::GetStdHeight()));
|
235
|
pane.Add(framelist.HSizePosZ(384, 0).TopPos(2, EditField::GetStdHeight()));
|
236
|
split.Horz(pane, tree.SizePos());
|
237
|
split.SetPos(8000);
|
238
|
Add(split);
|
239
|
|
240
|
disas.AddFrame(regs);
|
241
|
disas.WhenCursor = THISBACK(DisasCursor);
|
242
|
disas.WhenFocus = THISBACK(DisasFocus);
|
243
|
|
244
|
memory.WhenGoto = THISBACK(MemoryGoto);
|
245
|
|
246
|
tab <<= THISBACK(Tab);
|
247
|
|
248
|
framelist <<= THISBACK(SetFrame);
|
249
|
threadlist <<= THISBACK(SetThread);
|
250
|
|
251
|
watches.WhenAcceptEdit = THISBACK(Data);
|
252
|
watches.WhenDrop = THISBACK(DropWatch);
|
253
|
tab <<= THISBACK(Data);
|
254
|
|
255
|
tree.WhenOpen = THISBACK(TreeExpand);
|
256
|
|
257
|
FileIn in(ConfigFile("TreeTypes.txt"));
|
258
|
while(!in.IsEof()) {
|
259
|
String type = in.GetLine();
|
260
|
String desc = in.GetLine();
|
261
|
treetype.Add(type, desc);
|
262
|
}
|
263
|
StringStream ss(WorkspaceConfigData("pdb-debugger"));
|
264
|
Load(callback(this, &Pdb::SerializeSession), ss);
|
265
|
}
|
266
|
|
267
|
void Pdb::CleanupOnExit()
|
268
|
{
|
269
|
if(hProcess != INVALID_HANDLE_VALUE) {
|
270
|
while(threads.GetCount())
|
271
|
RemoveThread(threads.GetKey(0));
|
272
|
UnloadModuleSymbols();
|
273
|
SymCleanup(hProcess);
|
274
|
CloseHandle(hProcess);
|
275
|
hProcess = INVALID_HANDLE_VALUE;
|
276
|
}
|
277
|
}
|
278
|
|
279
|
void Pdb::CopyStack()
|
280
|
{
|
281
|
String s;
|
282
|
for(int i = 0; i < framelist.GetCount(); i++)
|
283
|
s << framelist.GetValue(i) << "\n";
|
284
|
WriteClipboardText(s);
|
285
|
}
|
286
|
|
287
|
void Pdb::CopyDisas()
|
288
|
{
|
289
|
disas.WriteClipboard();
|
290
|
}
|
291
|
|
292
|
Pdb::~Pdb()
|
293
|
{
|
294
|
SaveTree();
|
295
|
String fn = ConfigFile("TreeTypes.txt");
|
296
|
FileOut out(fn);
|
297
|
for(int i = 0; i < treetype.GetCount(); i++)
|
298
|
out << treetype.GetKey(i) << "\r\n" << treetype[i] << "\r\n";
|
299
|
StringStream ss;
|
300
|
Store(callback(this, &Pdb::SerializeSession), ss);
|
301
|
WorkspaceConfigData("pdb-debugger") = ss;
|
302
|
if(hProcess != INVALID_HANDLE_VALUE) {
|
303
|
if(!running)
|
304
|
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
|
305
|
TerminateProcess(hProcess, -1);
|
306
|
do {
|
307
|
if(!WaitForDebugEvent(&event, INFINITE))
|
308
|
break;
|
309
|
if(!ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE))
|
310
|
break;
|
311
|
}
|
312
|
while(event.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
|
313
|
CleanupOnExit();
|
314
|
}
|
315
|
StoreToGlobal(*this, CONFIGNAME);
|
316
|
IdeRemoveBottom(*this);
|
317
|
IdeRemoveRight(disas);
|
318
|
}
|
319
|
|
320
|
One<Debugger> PdbCreate(One<Host> host, const String& exefile, const String& cmdline)
|
321
|
{
|
322
|
One<Debugger> dbg;
|
323
|
if(!dbg.Create<Pdb>().Create(host, exefile, cmdline))
|
324
|
dbg.Clear();
|
325
|
return dbg;
|
326
|
}
|
327
|
|
328
|
#endif
|