-
Notifications
You must be signed in to change notification settings - Fork 21
/
debug_conn.ml
293 lines (255 loc) · 7.86 KB
/
debug_conn.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
[@@@warning "-27"]
type follow_fork_mode =
| Fork_parent
| Fork_child
type execution_summary =
| Event
| Breakpoint
| Exited
| Trap_barrier
| Uncaught_exc
type report = {
rep_type : execution_summary;
rep_event_count : int;
rep_stack_pointer : int;
rep_program_pointer : int;
}
type t = {
in_chan : Lwt_io.input_channel;
out_chan : Lwt_io.output_channel;
mutex : Lwt_mutex.t option;
}
let create in_chan out_chan =
{ in_chan; out_chan; mutex = Some (Lwt_mutex.create ()) }
let guard conn fn =
match conn.mutex with
| Some mutex -> (
Lwt_mutex.lock mutex;%lwt
(fn { conn with mutex = None })[%finally Lwt_mutex.unlock mutex; Lwt.return_unit]
)
| None -> fn conn
let initial conn =
guard conn (fun conn ->
let%lwt _ = Lwt_io.BE.read_int conn.in_chan in
let%lwt pid = Lwt_io.BE.read_int conn.in_chan in
Lwt.return pid
)
let stop conn =
guard conn (fun conn ->
try%lwt
Lwt_io.write_char conn.out_chan 's';%lwt
Lwt_io.flush conn.out_chan
with Sys_error _ | End_of_file -> Lwt.return_unit
)
let set_follow_fork_mode conn m =
guard conn (fun conn ->
let v = match m with Fork_parent -> 1 | Fork_child -> 0 in
Lwt_io.write_char conn.out_chan 'K';%lwt
Lwt_io.BE.write_int conn.out_chan v
)
let set_event conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'e';%lwt
Lwt_io.BE.write_int conn.out_chan pos
)
let set_breakpoint conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'B';%lwt
Lwt_io.BE.write_int conn.out_chan pos
)
let set_trap_barrier conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'b';%lwt
Lwt_io.BE.write_int conn.out_chan pos
)
let reset_instruction conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'i';%lwt
Lwt_io.BE.write_int conn.out_chan pos
)
let exec_with_trap_barrier conn trap_barrier func =
guard conn (fun conn ->
set_trap_barrier conn trap_barrier;%lwt
(func conn)[%finally set_trap_barrier conn 0]
)
let exec_with_temporary_breakpoint conn pos func =
guard conn (fun conn ->
set_breakpoint conn pos;%lwt
(func conn)[%finally reset_instruction conn pos]
)
let go conn n =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'g';%lwt
Lwt_io.BE.write_int conn.out_chan n;%lwt
let%lwt char = Lwt_io.read_char conn.in_chan in
let summary = match char with
| 'e' -> Event
| 'b' -> Breakpoint
| 'x' -> Exited
| 's' -> Trap_barrier
| 'u' -> Uncaught_exc
| _ -> assert false in
let%lwt event_counter = Lwt_io.BE.read_int conn.in_chan in
let%lwt stack_pos = Lwt_io.BE.read_int conn.in_chan in
let%lwt pc = Lwt_io.BE.read_int conn.in_chan in
Lwt.return {
rep_type = summary;
rep_event_count = event_counter;
rep_stack_pointer = stack_pos;
rep_program_pointer = pc;
}
)
let get_frame conn =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'f';%lwt
let%lwt stack_pos = Lwt_io.BE.read_int conn.in_chan in
let%lwt pc = Lwt_io.BE.read_int conn.in_chan in
Lwt.return (stack_pos, pc)
)
let set_frame conn stack_pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'S';%lwt
Lwt_io.BE.write_int conn.out_chan stack_pos
)
let initial_frame conn =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan '0';%lwt
let%lwt stack_pos = Lwt_io.BE.read_int conn.in_chan in
let%lwt pc = Lwt_io.BE.read_int conn.in_chan in
Lwt.return (stack_pos, pc)
)
let up_frame conn stack_size =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'U';%lwt
Lwt_io.BE.write_int conn.out_chan stack_size;%lwt
let%lwt stack_pos = Lwt_io.BE.read_int conn.in_chan in
if stack_pos = -1 then Lwt.return None
else (
let%lwt pc = Lwt_io.BE.read_int conn.in_chan in
Lwt.return (Some (stack_pos, pc))
)
)
let value_size = if 1 lsl 31 = 0 then 4 else 8
let input_remote_value conn =
guard conn (fun conn ->
let buf = Bytes.create value_size in
Lwt_io.read_into_exactly conn.in_chan buf 0 value_size;%lwt
Lwt.return (Bytes.to_string buf)
)
let output_remote_value conn value =
guard conn (fun conn ->
Lwt_io.write_from_string_exactly conn.out_chan value 0 value_size
)
module Remote_value = struct
type t =
| Remote of string
| Local of Obj.t
let same rv1 rv2 =
match rv1, rv2 with
| Local obj1, Local obj2 -> obj1 == obj2
| Remote rv1, Remote rv2 -> rv1 = rv2
| _ -> false
let repr x = Local (Obj.repr x)
let obj conn rv =
match rv with
| Local obj -> Lwt.return (Obj.obj obj)
| Remote rv ->
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'M';%lwt
output_remote_value conn rv;%lwt
Lwt_io.read_value conn.in_chan
)
let is_block rv =
match rv with
| Local obj -> Obj.is_block obj
| Remote rv -> Obj.is_block (Array.unsafe_get (Obj.magic rv : Obj.t array) 0)
let tag conn rv =
if not (is_block rv) then Lwt.return Obj.int_tag
else
match rv with
| Local obj -> Lwt.return (Obj.tag obj)
| Remote rv ->
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'H';%lwt
output_remote_value conn rv;%lwt
let%lwt header = Lwt_io.BE.read_int conn.in_chan in
Lwt.return (header land 0xFF)
)
let size conn rv =
match rv with
| Local obj -> Lwt.return (Obj.size obj)
| Remote rv ->
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'H';%lwt
output_remote_value conn rv;%lwt
let%lwt header = Lwt_io.BE.read_int conn.in_chan in
Lwt.return (
if header land 0xFF = Obj.double_array_tag && Sys.word_size = 32
then header lsr 11
else header lsr 10
)
)
let field conn rv idx =
match rv with
| Local obj -> Lwt.return (Local (Obj.field obj idx))
| Remote rv ->
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'F';%lwt
output_remote_value conn rv;%lwt
Lwt_io.BE.write_int conn.out_chan idx;%lwt
match%lwt Lwt_io.read_char conn.in_chan with
| '\000' ->
let%lwt value = input_remote_value conn in
Lwt.return (Remote value)
| '\001' ->
(* Not big-endian here *)
let%lwt value = Lwt_io.read_float64 conn.in_chan in
Lwt.return (Local (Obj.repr value))
| _ -> assert false
)
let local conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'L';%lwt
Lwt_io.BE.write_int conn.out_chan pos;%lwt
let%lwt rv = input_remote_value conn in
Lwt.return (Remote rv)
)
let from_environment conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'E';%lwt
Lwt_io.BE.write_int conn.out_chan pos;%lwt
let%lwt rv = input_remote_value conn in
Lwt.return (Remote rv)
)
let global conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'G';%lwt
Lwt_io.BE.write_int conn.out_chan pos;%lwt
let%lwt rv = input_remote_value conn in
Lwt.return (Remote rv)
)
let accu conn pos =
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'A';%lwt
let%lwt rv = input_remote_value conn in
Lwt.return (Remote rv)
)
let closure_code conn rv =
match rv with
| Local _ -> assert false
| Remote rv ->
guard conn (fun conn ->
Lwt_io.write_char conn.out_chan 'C';%lwt
output_remote_value conn rv;%lwt
Lwt_io.BE.read_int conn.in_chan
)
let pointer rv =
match rv with
| Local _ -> ""
| Remote rv ->
let bytes = ref [] in
String.iter (fun c -> bytes := c :: !bytes) rv;
let obytes = if Sys.big_endian then List.rev !bytes else !bytes in
let to_hex c = Printf.sprintf "%02x" (Char.code c) in
String.concat "" (List.map to_hex obytes)
end