1
|
1 /* Ddbg - Win32 Debugger for the D programming language
|
|
2 * Copyright (c) 2007 Jascha Wetzel
|
|
3 * All rights reserved. See LICENSE.TXT for details.
|
|
4 */
|
|
5 module breakpoint;
|
|
6
|
|
7 import std.string;
|
|
8 import std.c.string;
|
|
9
|
|
10 import dbgthread;
|
|
11 import codeview.codeview;
|
|
12 import dbgprocess;
|
|
13 import util;
|
|
14
|
|
15 import win32.windef;
|
|
16
|
|
17 enum StepMode {
|
|
18 e_in, e_over, e_out
|
|
19 }
|
|
20
|
|
21 /**************************************************************************************************
|
|
22 Represents a software breakpoint.
|
|
23 **************************************************************************************************/
|
|
24 class Breakpoint
|
|
25 {
|
|
26 //---------------------------------------------------------------------------------------------
|
|
27 // constants
|
|
28 const ubyte BREAKPOINT_OPCODE = 0xccu;
|
|
29
|
|
30 //---------------------------------------------------------------------------------------------
|
|
31 // variables
|
|
32 byte old_opcode;
|
|
33 bool active,
|
|
34 temporary,
|
|
35 deactivate_d_exception_handler,
|
|
36 propagate, /// when hit on a jmp/call/ret instruction, shall be reactivated on it's destination
|
|
37 hardware;
|
|
38 Breakpoint foreach_end;
|
|
39 Location location;
|
|
40 size_t frame_ptr,
|
|
41 threadId,
|
|
42 old_dr_value;
|
|
43 ubyte dr_index;
|
|
44
|
|
45 //---------------------------------------------------------------------------------------------
|
|
46 // properties
|
|
47 string file() { return location is null?null:location.file; }
|
|
48 uint line() { return location is null?0:location.line; }
|
|
49 uint address() { return location is null?0:location.address; }
|
|
50
|
|
51
|
|
52 //---------------------------------------------------------------------------------------------
|
|
53 // construction
|
|
54 this(Location loc, bool temp, uint _threadId, bool _hardware=false)
|
|
55 {
|
|
56 hardware = _hardware;
|
|
57 threadId = _threadId;
|
|
58 temporary = temp;
|
|
59 location = loc;
|
|
60 }
|
|
61
|
|
62
|
|
63 //---------------------------------------------------------------------------------------------
|
|
64 // methods
|
|
65
|
|
66 /**
|
|
67 *
|
|
68 */
|
|
69 string toString()
|
|
70 {
|
|
71 string tmp;
|
|
72 tmp.length = 100;
|
|
73 tmp.length = 0;
|
|
74 if ( location.path.length > 0 )
|
|
75 tmp ~= format("%s ", location.path);
|
|
76 if ( file.length > 0 )
|
|
77 tmp ~= format("%s:%d ", file, line);
|
|
78 if ( location.address > 0 )
|
|
79 tmp ~= format("0x%x ", location.address);
|
|
80 if ( hardware )
|
|
81 tmp ~= "hw ";
|
|
82 if ( threadId > 0 )
|
|
83 tmp ~= format("thread %s", threadId);
|
|
84 else
|
|
85 tmp ~= format("all threads");
|
|
86 return tmp;
|
|
87 }
|
|
88
|
|
89 /**********************************************************************************************
|
|
90 Restores the opcode that has been overwritten for the given breakpoint.
|
|
91 Returns success.
|
|
92 **********************************************************************************************/
|
|
93 bool deactivate(DbgProcess proc)
|
|
94 {
|
|
95 if ( !active )
|
|
96 return true;
|
|
97 if ( proc is null )
|
|
98 return false;
|
|
99
|
|
100 if ( hardware )
|
|
101 {
|
|
102 if ( threadId == 0 )
|
|
103 {
|
|
104 foreach ( thread; proc.threads.values )
|
|
105 clearHWBP(thread, 0);
|
|
106 }
|
|
107 else
|
|
108 clearHWBP(proc.threads[threadId], 0);
|
|
109 }
|
|
110 else if( !proc.writeProcessMemory(location.address, &old_opcode, ubyte.sizeof))
|
|
111 {
|
|
112 DbgIO.println("restoreBreakpoint(): Failed to write original opcode at 0x%x", location.address);
|
|
113 return false;
|
|
114 }
|
|
115
|
|
116 active = false;
|
|
117 return true;
|
|
118 }
|
|
119
|
|
120 /**********************************************************************************************
|
|
121 Writes an int 3 opcode at the address of this breakpoint, saving the overwritten code.
|
|
122 Returns success.
|
|
123 **********************************************************************************************/
|
|
124 bool activate(DbgProcess proc)
|
|
125 {
|
|
126 if( active )
|
|
127 return true;
|
|
128 if( location.address == 0 || proc is null )
|
|
129 return false;
|
|
130
|
|
131 debug DbgIO.println("activating bp at 0x%x", location.address);
|
|
132
|
|
133 if ( hardware )
|
|
134 {
|
|
135 if ( threadId == 0 )
|
|
136 {
|
|
137 foreach ( thread; proc.threads.values )
|
|
138 setHWBP(thread, location.address, 0);
|
|
139 }
|
|
140 else
|
|
141 setHWBP(proc.threads[threadId], location.address, 0);
|
|
142 }
|
|
143 else
|
|
144 {
|
|
145 uint oldprot, oldprot2;
|
|
146 ubyte ccByte = cast(ubyte)0xcc;
|
|
147
|
|
148 if( ubyte.sizeof > proc.readProcessMemory(location.address, &old_opcode, ubyte.sizeof) ) {
|
|
149 DbgIO.println( "readProcessMemory(): failed to read breakpoint opcode at 0x%08x", location.address );
|
|
150 return false;
|
|
151 }
|
|
152
|
|
153 ubyte opcode = BREAKPOINT_OPCODE;
|
|
154 if( ubyte.sizeof > proc.writeProcessMemory(location.address, &opcode, ubyte.sizeof) ) {
|
|
155 DbgIO.println("writeProcessMemory(): Failed to write breakpoint at 0x%08x", location.address );
|
|
156 return false;
|
|
157 }
|
|
158 }
|
|
159
|
|
160 active = true;
|
|
161 return true;
|
|
162 }
|
|
163
|
|
164 /**********************************************************************************************
|
|
165
|
|
166 **********************************************************************************************/
|
|
167 void setHWBP(DbgThread thread, size_t address, ubyte index)
|
|
168 {
|
|
169 assert(index < 4);
|
|
170
|
|
171 CONTEXT ctx;
|
|
172 thread.getContext(ctx, CONTEXT_DEBUG_REGISTERS);
|
|
173 DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
|
|
174
|
|
175 old_dr_value = *(&ctx.Dr0 + index);
|
|
176 *(&ctx.Dr0 + index) = address+thread.getDsBase;
|
|
177 dr_index = index;
|
|
178
|
|
179 ctx.Dr7 |= 1<<10 | (1 << index) | (15 << (16+index*4));
|
|
180 DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
|
|
181 thread.setContext(ctx);
|
|
182 }
|
|
183
|
|
184 /**********************************************************************************************
|
|
185
|
|
186 **********************************************************************************************/
|
|
187 void clearHWBP(DbgThread thread, ubyte index)
|
|
188 {
|
|
189 assert(index < 4);
|
|
190
|
|
191 CONTEXT ctx;
|
|
192 thread.getContext(ctx, CONTEXT_DEBUG_REGISTERS);
|
|
193 DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
|
|
194
|
|
195 ctx.Dr7 &= ~((1 << index) | (15 << (16+index*4)));
|
|
196 DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
|
|
197 thread.setContext(ctx);
|
|
198 }
|
|
199 }
|