Gdb.cpp

Gdb toolbar update & small toolbar fix - Zbigniew Rebacz, 11/19/2013 01:01 PM

Download (11.9 KB)

 
1
#include "Debuggers.h"
2

    
3
#define PROMPT "<\xcd\xeb>"
4

    
5
bool Gdb::Result(String& result, const String& s)
6
{
7
        int l = result.GetLength();
8
        result.Cat(s);
9
        const char *q = FindTag(~result + max(l - 5, 0), PROMPT);
10
        if(q) {
11
                result.Trim((int)(q - ~result));
12
                return true;
13
        }
14
        return false;
15
}
16

    
17
void Gdb::DebugBar(Bar& bar)
18
{
19
        bar.Add("Stop debugging", DbgImg::StopDebug(), THISBACK(Stop))
20
           .Key(K_SHIFT_F5);
21
        bar.Separator();
22
        bool b = !IdeIsDebugLock();
23
        bar.Add(b, "Step into", DbgImg::StepInto(), THISBACK1(Step, disas.HasFocus() ? "stepi"
24
                                                                                     : "step"))
25
           .Key(K_F11);
26
        bar.Add(b, "Step over", DbgImg::StepOver(), THISBACK1(Step, disas.HasFocus() ? "nexti"
27
                                                                                     : "next"))
28
           .Key(K_F10);
29
        bar.Add(b, "Step out", DbgImg::StepOut(), THISBACK1(Step, "finish"))
30
           .Key(K_SHIFT_F11);
31
        bar.Add(b, "Run to", DbgImg::RunTo(), THISBACK(DoRunTo))
32
           .Key(K_CTRL_F10);
33
        bar.Add(b, "Run", DbgImg::Run(), THISBACK(Run))
34
           .Key(K_F5);
35
        bar.MenuSeparator();
36
        bar.Add(b, "Quick watch", THISBACK(QuickWatch))
37
                   .Key(K_CTRL_Q);
38
        bar.MenuSeparator();
39
        bar.Add(b, "Copy backtrace", THISBACK(CopyStack));
40
        bar.Add(b, "Copy dissassembly", THISBACK(CopyDisas));
41
}
42

    
43
void Gdb::CopyStack()
44
{
45
        DropFrames();
46
        String s;
47
        for(int i = 0; i < frame.GetCount(); i++)
48
                s << frame.GetValue(i) << "\n";
49
        WriteClipboardText(s);
50
}
51

    
52
void Gdb::CopyDisas()
53
{
54
        disas.WriteClipboard();
55
}
56

    
57
int CharFilterReSlash(int c)
58
{
59
        return c == '\\' ? '/' : c;
60
}
61

    
62
String Bpoint(Host& host, const String& file, int line)
63
{
64
        return String().Cat() << Filter(host.GetHostPath(NormalizePath(file)), CharFilterReSlash) << ":" << line + 1;
65
}
66

    
67
bool Gdb::TryBreak(const char *text)
68
{
69
        return FindTag(FastCmd(text), "Breakpoint");
70
}
71

    
72
bool Gdb::SetBreakpoint(const String& filename, int line, const String& bp)
73
{
74
        String bi = Bpoint(*host, filename, line);
75
        if(bp.IsEmpty())
76
                FastCmd("clear " + bi);
77
        else if(bp[0]==0xe)
78
                FastCmd("b " + bi);
79
        else
80
                FastCmd("b " + bi + " if " + bp);
81
        return true;
82
}
83
void Gdb::SetDisas(const String& text)
84
{
85
        disas.Clear();
86
        StringStream ss(text);
87
        while(!ss.IsEof()) {
88
                String ln = ss.GetLine();
89
                CParser p(ln);
90
                if(p.Char2('0', 'x')) {
91
                        dword adr = p.IsNumber(16) ? p.ReadNumber(16) : 0;
92
                        String code;
93
                        String args;
94
                        int level = 0;
95
                        while(!p.IsEof()) {
96
                                if(p.Char(':') && level == 0)
97
                                        break;
98
                                else
99
                                if(p.Char('<'))
100
                                        level++;
101
                                else
102
                                if(p.Char('>'))
103
                                        level--;
104
                                else
105
                                        p.GetChar();
106
                        }
107
                        p.Spaces();
108
                        if(p.IsId()) {
109
                                code = p.ReadId();
110
                                for(;;) {
111
                                        if(p.Spaces())
112
                                                args.Cat(' ');
113
                                        if(p.IsEof())
114
                                                break;
115
                                        if(p.Char2('0', 'x')) {
116
                                                dword adr = 0;
117
                                                if(p.IsNumber(16))
118
                                                        adr = p.ReadNumber(16);
119
                                                String fname;
120
                                                bool   usefname = false;
121
                                                if(p.Char('<')) {
122
                                                        const char *b = p.GetPtr();
123
                                                        int level = 1;
124
                                                        usefname = true;
125
                                                        while(!p.IsEof()) {
126
                                                                if(p.Char('>') && --level == 0) {
127
                                                                        fname = String(b, p.GetPtr() - 1);
128
                                                                        break;
129
                                                                }
130
                                                                if(p.Char('<'))
131
                                                                        level++;
132
                                                                if(p.Char('+'))
133
                                                                        usefname = false;
134
                                                                else {
135
                                                                        p.GetChar();
136
                                                                        p.Spaces();
137
                                                                }
138
                                                        }
139
                                                }
140
                                                args << (usefname ? fname : Sprintf("0x%X", adr));
141
                                                disas.AddT(adr);
142
                                        }
143
                                        else
144
                                        if(p.Id("DWORD"))
145
                                                args.Cat("dword ");
146
                                        else
147
                                        if(p.Id("WORD"))
148
                                                args.Cat("word ");
149
                                        else
150
                                        if(p.Id("BYTE"))
151
                                                args.Cat("byte ");
152
                                        else
153
                                        if(p.Id("PTR"))
154
                                                args.Cat("ptr ");
155
                                        else
156
                                                args.Cat(p.GetChar());
157
                                }
158
                        }
159
                        disas.Add(adr, code, args);
160
                }
161
        }
162
}
163

    
164
void Gdb::SyncDisas(bool fr)
165
{
166
        if(!disas.IsVisible())
167
                return;
168
        if(!disas.InRange(addr))
169
                SetDisas(FastCmd("disas"));
170
        disas.SetCursor(addr);
171
        disas.SetIp(addr, fr ? DbgImg::FrameLinePtr() : DbgImg::IpLinePtr());
172
        String s = FastCmd("info registers");
173
        StringStream ss(s);
174
        for(int i = 0; i < reglbl.GetCount(); i++)
175
                reglbl[i]->SetInk(SColorText);
176
        while(!ss.IsEof()) {
177
                String ln = ss.GetLine();
178
                CParser p(ln);
179
                String name;
180
                if(p.IsId()) {
181
                        name = p.ReadId();
182
                        if(p.Char2('0', 'x')) {
183
                                String n = Sprintf("%08X", p.ReadNumber(16));
184
                                for(int i = 0; i < reglbl.GetCount(); i++) {
185
                                        if(regname[i] == name) {
186
                                                if(reglbl[i]->GetText() != n) {
187
                                                        reglbl[i]->SetLabel(n);
188
                                                        reglbl[i]->SetInk(LtRed);
189
                                                }
190
                                        }
191
                                }
192
                        }
193
                }
194
        }
195
}
196

    
197
String FormatFrame(const char *s)
198
{
199
        if(*s++ != '#')
200
                return Null;
201
        while(IsDigit(*s))
202
                s++;
203
        while(*s == ' ')
204
                s++;
205
        if(s[0] == '0' && ToUpper(s[1]) == 'X') {
206
                s += 2;
207
                while(IsXDigit(*s))
208
                        s++;
209
                while(*s == ' ')
210
                        s++;
211
                if(s[0] != 'i' && s[1] != 'n')
212
                        return Null;
213
                s += 2;
214
                while(*s == ' ')
215
                        s++;
216
        }
217
        if(!IsAlpha(*s))
218
                return Null;
219
        const char *w = strchr(s, '\r');
220
        if(w)
221
                return String(s, w);
222
        w = strchr(s, '\n');
223
        if(w)
224
                return String(s, w);
225
        return s;
226
}
227

    
228
bool ParsePos(const String& s, String& fn, int& line, adr_t & adr)
229
{
230
        const char *q = FindTag(s, "\x1a\x1a");
231
        if(!q) return false;
232
        q += 2;
233
        Vector<String> p = Split(q + 2, ':');
234
        p.SetCount(5);
235
        fn = String(q, q + 2) + p[0];
236
        line = atoi(p[1]);
237
        CParser pa(p[4]);
238
        pa.Char2('0', 'x');
239
        if(pa.IsNumber(16))
240
                adr = pa.ReadNumber(16);
241
        return true;
242
}
243

    
244
void Gdb::CheckEnd(const char *s)
245
{
246
        if(!dbg) {
247
                Stop();
248
                return;
249
        }
250
        if(FindTag(s, "Program exited normally.")) {
251
                Stop();
252
                return;
253
        }
254
        const char *q = FindTag(s, "Program exited with code ");
255
        if(q) {
256
                PutConsole(q);
257
                Stop();
258
                return;
259
        }
260
}
261

    
262
String Gdb::Cmdp(const char *cmdline, bool fr)
263
{
264
        String s = Cmd(cmdline);
265
        if(ParsePos(s, file, line, addr)) {
266
                IdeSetDebugPos(GetLocalPath(file), line - 1, fr ? DbgImg::FrameLinePtr()
267
                                                                : DbgImg::IpLinePtr(), 0);
268
                IdeSetDebugPos(GetLocalPath(file), line - 1,
269
                               disas.HasFocus() ? fr ? DbgImg::FrameLinePtr() : DbgImg::IpLinePtr()
270
                                                : Image(), 1);
271
                SyncDisas(fr);
272
                autoline = IdeGetLine(line - 2) + ' ' + IdeGetLine(line - 1) + ' ' + IdeGetLine(line);
273
        }
274
        else {
275
                file = Null;
276
                CParser pa(s);
277
                pa.Char2('0', 'x');
278
                if(pa.IsNumber(16))
279
                        addr = pa.ReadNumber(16);
280
                SyncDisas(fr);
281
        }
282
        frame.Clear();
283
        frame.Add(0, FormatFrame(Cmd("frame")));
284
        frame <<= 0;
285
        Data();
286
        return s;
287
}
288

    
289
bool Gdb::RunTo()
290
{
291
        String bi;
292
        bool df = disas.HasFocus();
293
        if(df) {
294
                if(!disas.GetCursor())
295
                        return false;
296
                bi = Sprintf("*0x%X", disas.GetCursor());
297
        }
298
        else
299
                bi = Bpoint(*host, IdeGetFileName(), IdeGetFileLine());
300
        if(!TryBreak("b " + bi)) {
301
                Exclamation("No code at chosen location !");
302
                return false;
303
        }
304
        String e = Cmdp(firstrun ? "run" : "continue");
305
        firstrun = false;
306
        FastCmd("clear " + bi);
307
        if(df)
308
                disas.SetFocus();
309
        CheckEnd(e);
310
        IdeActivateBottom();
311
        return true;
312
}
313

    
314
void Gdb::Run()
315
{
316
        CheckEnd(Cmdp(firstrun ? "run" : "continue"));
317
        firstrun = false;
318
        IdeActivateBottom();
319
}
320

    
321
void Gdb::Step(const char *cmd)
322
{
323
        bool b = disas.HasFocus();
324
        String s = Cmdp(cmd);
325
        if(b) disas.SetFocus();
326
        CheckEnd(s);
327
        IdeActivateBottom();
328
}
329

    
330
void Gdb::DisasCursor()
331
{
332
        if(!disas.HasFocus())
333
                return;
334
        int line;
335
        String file;
336
        adr_t addr;
337
        if(ParsePos(FastCmd(Sprintf("info line *0x%X", disas.GetCursor())), file, line, addr))
338
                IdeSetDebugPos(file, line - 1, DbgImg::DisasPtr(), 1);
339
        disas.SetFocus();
340
}
341

    
342
void Gdb::DisasFocus()
343
{
344
//        if(!disas.HasFocus())
345
//                IdeSetDebugPos(file, 0, Null, 1);
346
}
347

    
348
void Gdb::DropFrames()
349
{
350
        int i = 0;
351
        int q = ~frame;
352
        frame.Clear();
353
        for(;;) {
354
                String s = FormatFrame(FastCmd(Sprintf("frame %d", i)));
355
                if(IsNull(s)) break;
356
                frame.Add(i++, s);
357
        }
358
        frame <<= q;
359
}
360

    
361
void Gdb::ShowFrame()
362
{
363
        int i = (int)~frame;
364
        Cmdp(Sprintf("frame %d", i), i);
365
}
366

    
367
String DataClean(CParser& p)
368
{
369
        String r;
370
        if(p.Char('{')) {
371
                while(!p.IsEof() && !p.Char('}')) {
372
                        p.Id("static");
373
                        if(p.Char('<')) {
374
                                int level = 1;
375
                                while(level > 0)
376
                                        if(p.Char('<'))
377
                                                level++;
378
                                        else
379
                                        if(p.Char('>'))
380
                                                level--;
381
                                        else
382
                                                p.GetChar();
383
                                p.Spaces();
384
                                p.Char('=');
385
                                String q = DataClean(p);
386
                                if(!q.IsEmpty()) {
387
                                        if(!r.IsEmpty())
388
                                                r << ", ";
389
                                        r << q;
390
                                }
391
                        }
392
                        else
393
                        if(p.IsId()) {
394
                                String id = p.ReadId();
395
                                p.Char('=');
396
                                String q = DataClean(p);
397
                                if(!q.IsEmpty()) {
398
                                        if(!r.IsEmpty())
399
                                                r << ", ";
400
                                        r << id << "=" << q;
401
                                }
402
                        }
403
                        else {
404
                                p.GetChar();
405
                                p.Spaces();
406
                        }
407
                }
408
                if(!r.IsEmpty() && (*r != '{' || *r.Last() != '}'))
409

    
410
                        return '{' + r + '}';
411
                return r;
412
        }
413
        p.Spaces();
414
        for(;;) {
415
                bool sp = p.Spaces();
416
                if(p.IsChar('}') || p.IsChar(',') || p.IsEof())
417
                        break;
418
                if(sp)
419
                        r << ' ';
420
                if(p.IsString())
421
                        r << AsCString(p.ReadString());
422
                else
423
                        r.Cat(p.GetChar());
424
        }
425
        return r;
426
}
427

    
428
String DataClean(const char *s)
429
{
430
        CParser p(s);
431
        return DataClean(p);
432
}
433

    
434
void Gdb::Locals()
435
{
436
        VectorMap<String, String> prev = DataMap(locals);
437
        locals.Clear();
438
        String s = FastCmd("info locals");
439
        StringStream ss(s);
440
        while(!ss.IsEof()) {
441
                String ln = ss.GetLine();
442
                const char *s = ln;
443
                const char *q = strchr(s, '=');
444
                if(!q) break;
445
                const char *e = q;
446
                while(e > s && e[-1] == ' ')
447
                        e--;
448
                q++;
449
                while(*q == ' ')
450
                        q++;
451
                locals.Add(String(s, e), DataClean(q));
452
        }
453
        MarkChanged(prev, locals);
454
}
455

    
456
String Gdb::Print(const String& exp)
457
{
458
        String q = FastCmd("print " + exp);
459
        StringStream ss(q);
460
        String ln = ss.GetLine();
461
        const char *s = strchr(ln, '=');
462
        if(s) {
463
                s++;
464
                while(*s == ' ')
465
                        s++;
466
                return DataClean(s);
467
        }
468
        else
469
                return DataClean(ln);
470
}
471

    
472
void Gdb::Watches()
473
{
474
        VectorMap<String, String> prev = DataMap(watches);
475
        for(int i = 0; i < watches.GetCount(); i++)
476
                watches.Set(i, 1, Print(watches.Get(i, 0)));
477
        MarkChanged(prev, watches);
478
}
479

    
480
void Gdb::Autos()
481
{
482
        VectorMap<String, String> prev = DataMap(autos);
483
        autos.Clear();
484
        CParser p(autoline);
485
        while(!p.IsEof()) {
486
                if(p.IsId()) {
487
                        String exp = p.ReadId();
488
                        for(;;) {
489
                                if(p.Char('.') && p.IsId())
490
                                        exp << '.';
491
                                else
492
                                if(p.Char2('-', '>') && p.IsId())
493
                                        exp << "->";
494
                                else
495
                                        break;
496
                                exp << p.ReadId();
497
                        }
498
                        if(autos.Find(exp) < 0) {
499
                                String val = Print(exp);
500
                                if(!IsNull(val) && val.Find('(') < 0)
501
                                        autos.Add(exp, val);
502
                        }
503
                }
504
                p.SkipTerm();
505
        }
506
        autos.Sort();
507
        MarkChanged(prev, autos);
508
}
509

    
510
void Gdb::QuickWatch()
511
{
512
        for(;;) {
513
                int q = quickwatch.Run();
514
                if(q == IDCANCEL)
515
                        break;
516
                FastCmd("set print pretty on");
517
                String s = FastCmd("p " + (String)~quickwatch.expression);
518
                const char *a = strchr(s, '=');
519
                if(a) {
520
                        a++;
521
                        while(*a == ' ')
522
                                a++;
523
                        quickwatch.value <<= a;
524
                        quickwatch.expression.AddHistory();
525
                }
526
                else
527
                        quickwatch.value <<= s;
528
                FastCmd("set print pretty off");
529
        }
530
        quickwatch.Close();
531
}
532

    
533
void Gdb::Data()
534
{
535
        switch(tab.Get()) {
536
        case 0: Watches(); break;
537
        case 1: Locals(); break;
538
        case 2: Autos(); break;
539
        }
540
}
541

    
542
bool Gdb::Key(dword key, int count)
543
{
544
        if(key >= 32 && key < 65535 && tab.Get() == 2) {
545
                watches.DoInsertAfter();
546
                Ctrl* f = GetFocusCtrl();
547
                if(f && watches.HasChildDeep(f))
548
                        f->Key(key, count);
549
                return true;
550
        }
551
        return Ctrl::Key(key, count);
552
}
553

    
554
bool Gdb::Create(One<Host> _host, const String& exefile, const String& cmdline)
555
{
556
        host = _host;
557
        dbg = host->StartProcess("gdb " + GetHostPath(exefile));
558
        if(!dbg) {
559
                Exclamation("Error invoking gdb !");
560
                return false;
561
        }
562
        IdeSetBottom(*this);
563
        IdeSetRight(disas);
564

    
565
        disas.AddFrame(regs);
566
        disas.WhenCursor = THISBACK(DisasCursor);
567
        disas.WhenFocus = THISBACK(DisasFocus);
568
        frame.WhenDrop = THISBACK(DropFrames);
569
        frame <<= THISBACK(ShowFrame);
570

    
571
        watches.WhenAcceptEdit = THISBACK(Data);
572
        tab <<= THISBACK(Data);
573

    
574
        Cmd("set prompt " PROMPT);
575
        Cmd("set disassembly-flavor intel");
576
        Cmd("set exec-done-display off");
577
        Cmd("set annotate 1");
578
        Cmd("set height 0");
579
        Cmd("set width 0");
580
        Cmd("set confirm off");
581
        Cmd("set print asm-demangle");
582

    
583
        if(!IsNull(cmdline))
584
                Cmd("set args " + cmdline);
585

    
586

    
587
        firstrun = true;
588

    
589
        return true;
590
}
591

    
592
Gdb::~Gdb()
593
{
594
        IdeRemoveBottom(*this);
595
        IdeRemoveRight(disas);
596
}
597

    
598
One<Debugger> GdbCreate(One<Host> host, const String& exefile, const String& cmdline)
599
{
600
        Gdb *dbg = new Gdb;
601
        if(!dbg->Create(host, exefile, cmdline)) {
602
                delete dbg;
603
                return NULL;
604
        }
605
        return dbg;
606
}