1 '''
2 GDB support
3 '''
4 import os
5 import re
6 import code
7 import time
8 import socket
9 import struct
10 import platform
11 import tempfile
12
13 import PE
14 import vdb
15 import envi
16 import envi.bits as e_bits
17 import envi.resolver as e_resolv
18 import vtrace
19
20 import envi.registers as e_registers
21 import vtrace.platforms.base as v_base
22
23 '''
24 VMWare config options...
25 debugStub.listen.guest64 = "TRUE" # ends up on port 8864 (or next avail)
26 debugStub.listen.guest32 = "TRUE" # .... 8832
27
28 debugStub.listen.guest32.remote = "TRUE"
29
30 debugStub.hideBreakpoints = "TRUE" # Enable breakpoints
31
32 From GDB stuff...
33 ===== i386
34 src/gdb/i386-tdep.c
35 src/gdb/regformats/reg-i386.dat
36 ===== amd64
37 src/gdb/amd64-tdep.c
38 src/gdb/regformats/reg-x86-64.dat
39 ===== arm
40 name:arm
41 expedite:r11,sp,pc
42 32:r0
43 32:r1
44 32:r2
45 32:r3
46 32:r4
47 32:r5
48 32:r6
49 32:r7
50 32:r8
51 32:r9
52 32:r10
53 32:r11
54 32:r12
55 32:sp
56 32:lr
57 32:pc
58 96:f0
59 96:f1
60 96:f2
61 96:f3
62 96:f4
63 96:f5
64 96:f6
65 96:f7
66 32:fps
67 32:cpsr
68 '''
69
70 gdb_reg_defs = {
71 'i386': (
72 ['eax','ecx','edx','ebx','esp','ebp','esi','edi','eip','eflags','cs','ss','ds','es','fs','gs'
73 ],
74 '<16I'
75 ),
76
77 'amd64': (
78 ['rax','rbx','rcx','rdx','rsi','rdi','rbp','rsp',
79 'r8','r9','r10','r11','r12','r13','r14','r15','rip',
80 'eflags','cs','ss','ds','es','fs','gs',
81
82
83 ],
84
85
86 '<17Q7L'
87 ),
88
89
90 'arm': (
91 ["r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","sl","fp","ip","sp",
92 "lr","pc", None, "cpsr"],
93 '<16I96sI'
94 ),
95 }
96
97 exit_types = ('X', 'W')
98
100 return '$%s#%.2x' % (cmd, csum(cmd))
101
103 sum = 0
104 for b in bytes:
105 sum += ord(b)
106 return sum & 0xff
107
108 SIGINT = 2
109 SIGTRAP = 5
110
111 trap_sigs = (SIGINT, SIGTRAP)
112
115
117
121
122 - def notify(self, event, trace):
126
128
129 - def __init__(self, host=None, port=None):
130 self._gdb_host = host
131 self._gdb_port = port
132 self._gdb_sock = None
133
134 self._gdb_filemagic = None
135
136
137 self._gdb_regfmt = ''
138 self._gdb_regsize = 0
139 self._gdb_reg_xlat = []
140 self._gdb_regnames = []
141
142 self.breaking = False
143
145 ret = ''
146 while not ret.endswith(c):
147 x = self._gdb_sock.recv(1)
148 if len(x) == 0:
149 raise Exception('socket closed prematurely!')
150 ret += x
151 return ret
152
154 b = self._gdb_sock.recv(1)
155 if len(b) == 0:
156 raise GdbServerDisconnected()
157
158 if b != '$':
159 raise Exception('Invalid Pkt Beginning! ->%s<-' % b)
160
161 bytes = self._recvUntil('#')
162 bytes = bytes[:-1]
163
164 isum = int(self._gdb_sock.recv(2), 16)
165 ssum = csum(bytes)
166 if isum != ssum:
167 raise Exception('Invalid Checksum! his: 0x%.2x ours: 0x%.2x' % (isum, ssum))
168
169 self._gdb_sock.sendall('+')
170
171
172 return bytes
173
177
179
180 self._gdb_sock.sendall(pkt(cmd))
181 b = self._gdb_sock.recv(1)
182 if b != '+':
183 raise Exception('Retrans! ->%s<-' % b)
184
186 if self._gdb_sock != None:
187 self._gdb_sock.shutdown(2)
188
189 tries = 0
190 while tries < 10:
191 self._gdb_sock = socket.socket()
192 try:
193 self._gdb_sock.connect( (self._gdb_host, self._gdb_port) )
194
195
196 try:
197 self._gdb_sock.settimeout(1)
198 self._gdb_sock.recv(1)
199 self._gdb_sock.sendall('+')
200
201 except socket.timeout, t:
202 pass
203
204 self._gdb_sock.settimeout(None)
205 break
206
207 except Exception, e:
208 time.sleep(0.2)
209 tries += 1
210
212 resp = ''
213 cmd = 'qRcmd,%s' % cmd.encode('hex')
214 pkt = self._cmdTransact(cmd)
215 while not pkt.startswith('OK'):
216 self._raiseIfError(pkt)
217 if not pkt.startswith('O'):
218 return pkt.decode('hex')
219 resp += pkt[1:].decode('hex')
220 pkt = self._recvPkt()
221 return resp
222
239
246
247
253
259
270
279
372
379
381
382
383
384 self._gdb_regfmt = fmt
385 self._gdb_regnames = names
386
387 self._gdb_reg_xlat = []
388 self._gdb_regsize = struct.calcsize(fmt)
389
390
391 for i,name in enumerate(names):
392 if name == None:
393 continue
394 j = self.getRegisterIndex(name)
395 if j != None:
396 self._gdb_reg_xlat.append( (i, j) )
397
410
424
444
446 if msg.startswith('E'):
447 raise Exception('Error: %s' % msg)
448
450
451 i = buf.find('*')
452 while i != -1:
453 cnt = ord(buf[i+1]) - 29
454 pad = buf[i-1] * cnt
455 buf = buf[:i] + pad + buf[i+2:]
456
457 i = buf.find('*')
458
459 return buf.decode('hex')
460
473
478
481
482
483
485
487
488 self.stepping = False
489 self.attaching = False
490 self.breaking = False
491
492 self.bigmask = e_bits.u_maxes[ self.getPointerSize() ]
493
494 aname = self.getMeta('Architecture')
495 self._addArchNamespace(aname)
496
497 self.setMeta('Platform', 'gdbstub')
498
499 self.setMeta('GdbServerHost', 'localhost')
500 self.setMeta('GdbServerPort', 0)
501 self.setMeta('GdbPlatform', 'Unknown')
502 self.setMeta('GdbTargetPlatform', 'Unknown')
503
504 self.setMeta('BinaryFormat', None)
505
506 arch_reg_info = gdb_reg_defs.get(aname)
507 if arch_reg_info == None:
508 raise Exception('We dont know the GDB register definition for arch: %s' % name)
509
510 self._arch_regnames, self._arch_regfmt = arch_reg_info
511 self._arch_regsize = struct.calcsize(self._arch_regfmt)
512
513 self._arch_rctx = self.arch.archGetRegCtx()
514 self._arch_reg_xlat = []
515 for i,name in enumerate(self._arch_regnames):
516 if name == None:
517 continue
518 j = self._arch_rctx.getRegisterIndex(name)
519 if j != None:
520 self._arch_reg_xlat.append((i,j))
521
522
523 e_registers.RegisterContext.__init__(self)
524 rinfo = self._arch_rctx.getRegisterInfo(meta=True)
525 self.setRegisterInfo(rinfo)
526
528 if aname == 'arm':
529 import vstruct.defs.arm7 as vs_arm7
530 self.vsbuilder.addVStructNamespace('arm7', vs_arm7)
531
533
534 basename = fname.split('/')[-1].split('\\')[-1]
535 return basename.split(".")[0].split("-")[0].lower()
536
539
569
572
574 '''
575 Use VMWare's monitor extension to get a register we wouldn't
576 normally have...
577 '''
578
579 fsstr = self._monitorCommand('r %s' % rname)
580 fsparts = fsstr.split()
581 return int(fsparts[3], 16)
582
584 istr = self._monitorCommand('r idtr')
585 m = re.match('.* base=(0x\w+) .*', istr)
586 idtr = long(m.groups()[0], 0)
587 return idtr
588
590 x1, kptr, x2 = self.readMemoryFormat(idtr, '<IQI')
591 try:
592 kptr -= kptr & 0xfff
593 while not self.readMemory(kptr, 16).startswith('MZ\x90\x00'):
594 kptr -= 4096
595 return kptr
596 except Exception, e:
597 return None
598
600
601 self.setVariable('fsbase', fsbase)
602
603 fs_fields = self.readMemoryFormat(fsbase, '<8I')
604
605
606 if fs_fields[7] == fsbase:
607
608
609 import vstruct.defs.windows.win_5_1_i386.ntoskrnl as vs_w_ntoskrnl
610 self.vsbuilder.addVStructNamespace('nt', vs_w_ntoskrnl)
611
612 self.setMeta('GdbTargetPlatform', 'Windows')
613 self.casesens = False
614
615 kpcr = self.getStruct('nt.KPCR', fsbase)
616 kver = self.getStruct('nt.DBGKD_GET_VERSION64', kpcr.KdVersionBlock)
617
618
619
620
621 kernbase = kver.KernBase & self.bigmask
622 modlist = kver.PsLoadedModuleList & self.bigmask
623
624 self.setVariable('PsLoadedModuleList', modlist)
625 self.setVariable('KernelBase', kernbase)
626
627 self.platformParseBinary = self.platformParseBinaryPe
628
629 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
630
631 self.addLibraryBase('nt', kernbase, always=True)
632 ldr_entry = self.readMemoryFormat(modlist, '<I')[0]
633 while ldr_entry != modlist:
634 ldte = self.getStruct('nt.LDR_DATA_TABLE_ENTRY', ldr_entry)
635 dllname = self.readMemory(ldte.FullDllName.Buffer, ldte.FullDllName.Length).decode('utf-16le')
636 dllbase = ldte.DllBase & self.bigmask
637 self.addLibraryBase(dllname, dllbase, always=True)
638 ldr_entry = ldte.InLoadOrderLinks.Flink & self.bigmask
639
640 try:
641 self.addBreakpoint(KeBugCheckBreak('nt.KeBugCheck'))
642 except Exception, e:
643 print 'Error Seting KeBugCheck Bp: %s' % e
644
645 try:
646 self.addBreakpoint(KeBugCheckBreak('nt.KeBugCheckEx'))
647 except Exception, e:
648 print 'Error Seting KeBugCheck Bp: %s' % e
649
650 else:
651
652 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
653
655 psize = self.getPointerSize()
656 vercmd = self._monitorCommand('version')
657
658 monhelp = self._monitorCommand('help')
659
660 if monhelp.find('netdev_add') != -1:
661
662 self.setMeta('GdbPlatform', 'Qemu32')
663
664 fsbase = None
665 monreg = self._monitorCommand('info registers')
666 for line in monreg.split('\n'):
667 if not line.startswith('FS'):
668 continue
669 parts = line.split()
670 fsbase = int(parts[2], 16)
671 break
672
673 self._enumTargetOs(fsbase)
674
675
676
677
678
679 elif monhelp.find('linuxoffsets') != -1:
680
681 self.setMeta('GdbPlatform', 'VMware%d' % (psize * 8))
682
683 if psize == 4:
684 fsbase = self._getVmwareReg('fs')
685 self._enumTargetOs(fsbase)
686
687 else:
688
689 idtr = self._getVmwareIdtr()
690 self.setVariable('idtr', idtr)
691
692 win_kpcr = 0x07fffffde000
693
694 fields = [-1,]
695 try:
696 fields = self.readMemoryFormat(win_kpcr, '<7Q')
697 except Exception, e:
698 print 'Exception:',e
699
700
701 if fields[-1] == win_kpcr:
702 self._initWin64(win_kpcr)
703 else:
704 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724 elif vercmd.lower().find('open on-chip debugger') != -1:
725
726 self.setMeta('GdbPlatform', 'OpenOCD')
727 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
728
729 else:
730 print 'Unidentified gdbstub: %s' % vercmd
731 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
732
733
734
736
737 import vstrct.defs.windows.win_6_1_amd64.ntoskrnl as vs_w_ntoskrnl
738 self.vsbuilder.addVStructNamespace('nt', vs_w_ntoskrnl)
739 self._initWinBase()
740
741
742
743
744
745
746
747
748
749
750
752
753 self.setMeta('GdbTargetPlatform', 'Windows')
754 self.casesens = False
755
756 kpcr = self.getStruct('nt.KPCR', kpcr)
757 kver = self.getStruct('nt.DBGKD_GET_VERSION64', kpcr.KdVersionBlock)
758
759 kernbase = kver.KernBase & self.bigmask
760 modlist = kver.PsLoadedModuleList & self.bigmask
761
762 self.setVariable('PsLoadedModuleList', modlist)
763 self.setVariable('KernelBase', kernbase)
764
765 self.platformParseBinary = self.platformParseBinaryPe
766
767 self.fireNotifiers(vtrace.NOTIFY_ATTACH)
768
769 self.addLibraryBase('nt', kernbase, always=True)
770 ldr_entry = self.readMemoryFormat(modlist, '<P')[0]
771 while ldr_entry != modlist:
772 ldte = self.getStruct('nt.LDR_DATA_TABLE_ENTRY', ldr_entry)
773 dllname = self.readMemory(ldte.FullDllName.Buffer, ldte.FullDllName.Length).decode('utf-16le')
774 dllbase = ldte.DllBase & self.bigmask
775 self.addLibraryBase(dllname, dllbase, always=True)
776 ldr_entry = ldte.InLoadOrderLinks.Flink & self.bigmask
777
778 try:
779 self.addBreakpoint(KeBugCheckBreak('nt.KeBugCheck'))
780 except Exception, e:
781 print 'Error Seting KeBugCheck Bp: %s' % e
782
783 try:
784 self.addBreakpoint(KeBugCheckBreak('nt.KeBugCheckEx'))
785 except Exception, e:
786 print 'Error Seting KeBugCheck Bp: %s' % e
787
788
789 GDB_BP_SOFTWARE = 0
790 GDB_BP_HARDWARE = 1
791 GDB_BP_WATCH_WRITE = 2
792 GDB_BP_WATCH_READ = 3
793 GDB_BP_WATCH_ACCESS = 4
794
795 -class GdbStubTrace(
796 vtrace.Trace,
797 GdbStubMixin,
798 v_base.TracerBase):
799
809
810
811
812
813
814
815
816
822
824 '''
825 Cleanup any non-fastbreak breakpoints. This routine doesn't even get
826 called in the event of mode FastBreak=True.
827 '''
828 self.fb_bp_done = False
829 for bp in self.breakpoints.itervalues():
830
831
832 if force or not bp.fastbreak:
833 self._cmdTransact('z%d,%x,%x' % (GDB_BP_SOFTWARE,bp.getAddress(),1))
834 bp.active = False
835
836
838 """
839 Check to see if we've landed on a breakpoint, and if so
840 deactivate and step us past it.
841
842 WARNING: Unfortunatly, cause this is used immidiatly before
843 a call to run/wait, we must block briefly even for the GUI
844 """
845
846
847 bp = self.curbp
848 if bp != None and bp.isEnabled():
849
850 orig = self.getMode("FastStep")
851 self.setMode("FastStep", True)
852 self.stepi()
853 self.setMode("FastStep", orig)
854 self._activateBreak(bp)
855
862