google-cloud-debugger 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +8 -0
  3. data/LICENSE +201 -0
  4. data/README.md +56 -0
  5. data/ext/google/cloud/debugger/debugger_c/debugger.c +31 -0
  6. data/ext/google/cloud/debugger/debugger_c/debugger.h +26 -0
  7. data/ext/google/cloud/debugger/debugger_c/evaluator.c +78 -0
  8. data/ext/google/cloud/debugger/debugger_c/evaluator.h +25 -0
  9. data/ext/google/cloud/debugger/debugger_c/extconf.rb +22 -0
  10. data/ext/google/cloud/debugger/debugger_c/tracer.c +478 -0
  11. data/ext/google/cloud/debugger/debugger_c/tracer.h +31 -0
  12. data/lib/google-cloud-debugger.rb +121 -0
  13. data/lib/google/cloud/debugger.rb +379 -0
  14. data/lib/google/cloud/debugger/agent.rb +204 -0
  15. data/lib/google/cloud/debugger/async_actor.rb +290 -0
  16. data/lib/google/cloud/debugger/breakpoint.rb +382 -0
  17. data/lib/google/cloud/debugger/breakpoint/evaluator.rb +1113 -0
  18. data/lib/google/cloud/debugger/breakpoint/source_location.rb +75 -0
  19. data/lib/google/cloud/debugger/breakpoint/stack_frame.rb +109 -0
  20. data/lib/google/cloud/debugger/breakpoint/variable.rb +304 -0
  21. data/lib/google/cloud/debugger/breakpoint_manager.rb +217 -0
  22. data/lib/google/cloud/debugger/credentials.rb +41 -0
  23. data/lib/google/cloud/debugger/debuggee.rb +204 -0
  24. data/lib/google/cloud/debugger/debuggee/app_uniquifier_generator.rb +78 -0
  25. data/lib/google/cloud/debugger/middleware.rb +77 -0
  26. data/lib/google/cloud/debugger/project.rb +135 -0
  27. data/lib/google/cloud/debugger/rails.rb +141 -0
  28. data/lib/google/cloud/debugger/service.rb +130 -0
  29. data/lib/google/cloud/debugger/tracer.rb +165 -0
  30. data/lib/google/cloud/debugger/transmitter.rb +129 -0
  31. data/lib/google/cloud/debugger/v2.rb +15 -0
  32. data/lib/google/cloud/debugger/v2/controller2_client.rb +299 -0
  33. data/lib/google/cloud/debugger/v2/controller2_client_config.json +43 -0
  34. data/lib/google/cloud/debugger/v2/debugger2_client.rb +378 -0
  35. data/lib/google/cloud/debugger/v2/debugger2_client_config.json +53 -0
  36. data/lib/google/cloud/debugger/v2/doc/google/devtools/clouddebugger/v2/data.rb +441 -0
  37. data/lib/google/cloud/debugger/v2/doc/google/devtools/clouddebugger/v2/debugger.rb +151 -0
  38. data/lib/google/cloud/debugger/v2/doc/google/devtools/source/v1/source_context.rb +161 -0
  39. data/lib/google/cloud/debugger/v2/doc/google/protobuf/timestamp.rb +81 -0
  40. data/lib/google/cloud/debugger/version.rb +22 -0
  41. data/lib/google/devtools/clouddebugger/v2/controller_pb.rb +47 -0
  42. data/lib/google/devtools/clouddebugger/v2/controller_services_pb.rb +97 -0
  43. data/lib/google/devtools/clouddebugger/v2/data_pb.rb +105 -0
  44. data/lib/google/devtools/clouddebugger/v2/debugger_pb.rb +74 -0
  45. data/lib/google/devtools/clouddebugger/v2/debugger_services_pb.rb +64 -0
  46. data/lib/google/devtools/source/v1/source_context_pb.rb +89 -0
  47. metadata +300 -0
@@ -0,0 +1,478 @@
1
+ /*
2
+ Copyright 2017 Google Inc. All rights reserved.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ #include "ruby/ruby.h"
18
+ #include "ruby/debug.h"
19
+ #include "tracer.h"
20
+
21
+ /**
22
+ * hash_get_keys_callback
23
+ * Helper callback function for hash_get_keys.
24
+ */
25
+ static int
26
+ hash_get_keys_callback(VALUE key, VALUE val, VALUE key_ary)
27
+ {
28
+ rb_ary_push(key_ary, key);
29
+
30
+ return ST_CONTINUE;
31
+ }
32
+
33
+ /**
34
+ * hash_get_keys
35
+ * Helper function to return an array of all the keys of a given Ruby array
36
+ */
37
+ static VALUE
38
+ hash_get_keys(VALUE hash)
39
+ {
40
+ VALUE key_ary;
41
+
42
+ if(!RB_TYPE_P(hash, T_HASH)) {
43
+ return Qnil;
44
+ }
45
+
46
+ key_ary = rb_ary_new();
47
+
48
+ rb_hash_foreach(hash, hash_get_keys_callback, key_ary);
49
+
50
+ return key_ary;
51
+ }
52
+
53
+ /**
54
+ * match_breakpoints_files
55
+ * Check the Tracer#breakpoints_cache if any breakpoints match the given
56
+ * tracepoint_path. Return 1 if found. Otherwise 0;
57
+ */
58
+ static VALUE
59
+ match_breakpoints_files(VALUE self, VALUE tracepoint_path)
60
+ {
61
+ int i;
62
+ char *c_tracepoint_path = rb_string_value_cstr(&tracepoint_path);
63
+
64
+ VALUE path_breakpoints_hash = rb_iv_get(self, "@breakpoints_cache");
65
+ VALUE breakpoints_paths = hash_get_keys(path_breakpoints_hash);
66
+ VALUE *c_breakpoints_paths = RARRAY_PTR(breakpoints_paths);
67
+ int breakpoints_paths_len = RARRAY_LEN(breakpoints_paths);
68
+
69
+ for (i = 0; i < breakpoints_paths_len; i++) {
70
+ VALUE breakpoint_path = c_breakpoints_paths[i];
71
+ char *c_breakpoint_path = rb_string_value_cstr(&breakpoint_path);
72
+
73
+ if (strcmp(c_tracepoint_path, c_breakpoint_path) == 0) {
74
+ return 1;
75
+ }
76
+ }
77
+
78
+ return 0;
79
+ }
80
+
81
+ static VALUE
82
+ disable_line_trace_for_thread(VALUE thread);
83
+
84
+ /**
85
+ * match_breakpoints
86
+ * Check the Tracer#breakpoints_cache for any matching breakpoints of given
87
+ * file path and line number.
88
+ *
89
+ * Return a Ruby array of breakpoints found. Qtrue if no match found, but this
90
+ * file contains at least one breakpoint. Qnil if event triggered in a file
91
+ * that doesn't contain any breakpoints.
92
+ */
93
+ static VALUE
94
+ match_breakpoints(VALUE self, const char *c_trace_path, int c_trace_lineno)
95
+ {
96
+ int i, j;
97
+ VALUE path_breakpoints_hash = rb_iv_get(self, "@breakpoints_cache");
98
+ VALUE breakpoints_paths = hash_get_keys(path_breakpoints_hash);
99
+ VALUE *c_breakpoints_paths = RARRAY_PTR(breakpoints_paths);
100
+ int breakpoints_paths_len = RARRAY_LEN(breakpoints_paths);
101
+ VALUE path_match = Qnil;
102
+
103
+ // Check the file paths of @breakpoints_cache
104
+ for (i = 0; i < breakpoints_paths_len; i++) {
105
+ VALUE breakpoint_path = c_breakpoints_paths[i];
106
+ char *c_breakpoint_path = rb_string_value_cstr(&breakpoint_path);
107
+
108
+ // Found matching file path, keep going and check for the line numbers
109
+ if (strcmp(c_trace_path, c_breakpoint_path) == 0) {
110
+ VALUE line_breakpoint_hash = rb_hash_aref(path_breakpoints_hash, breakpoint_path);
111
+ VALUE breakpoints_lines = hash_get_keys(line_breakpoint_hash);
112
+ VALUE *c_breakpoints_lines = RARRAY_PTR(breakpoints_lines);
113
+ int breakpoints_lines_len = RARRAY_LEN(breakpoints_lines);
114
+ path_match = Qtrue;
115
+
116
+ // Found matching breakpoints. Return the cached breakpoints array
117
+ for (j = 0; j < breakpoints_lines_len; j++) {
118
+ VALUE breakpoint_lineno = c_breakpoints_lines[j];
119
+ int c_breakpoint_lineno = NUM2INT(breakpoint_lineno);
120
+
121
+ if (c_trace_lineno == c_breakpoint_lineno) {
122
+ return rb_hash_aref(line_breakpoint_hash, breakpoint_lineno);
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ return path_match;
129
+ }
130
+
131
+ /**
132
+ * line_trace_callback
133
+ * Callback function for thread line event tracing. It checks tracer#breakpoint_cache
134
+ * for any breakpoints trigger on current line called. Then trigger evaluation
135
+ * procedure if found matching breakpoints. It also skip breakpoints that are
136
+ * already marked completed.
137
+ */
138
+ static void
139
+ line_trace_callback(rb_event_flag_t event, VALUE data, VALUE obj, ID mid, VALUE klass)
140
+ {
141
+ VALUE self = data;
142
+ const char *c_trace_path = rb_sourcefile();
143
+ int c_trace_lineno = rb_sourceline();
144
+ VALUE trace_binding;
145
+ VALUE call_stack_bindings;
146
+
147
+ int i;
148
+ VALUE matching_result = match_breakpoints(self, c_trace_path, c_trace_lineno);
149
+ VALUE *c_matching_breakpoints;
150
+ VALUE matching_breakpoint;
151
+ int matching_breakpoints_len;
152
+
153
+ // If matching result isn't an array, it means we're in completely wrong file,
154
+ // or not on the right line. Turn line tracing off if we're in wrong file.
155
+ if (!RB_TYPE_P(matching_result, T_ARRAY)) {
156
+ if (!RTEST(matching_result)) {
157
+ disable_line_trace_for_thread(Qnil);
158
+ }
159
+ return;
160
+ }
161
+
162
+ c_matching_breakpoints = RARRAY_PTR(matching_result);
163
+ matching_breakpoints_len = RARRAY_LEN(matching_result);
164
+ trace_binding = rb_binding_new();
165
+ call_stack_bindings = rb_funcall(trace_binding, rb_intern("callers"), 0);
166
+ rb_ary_pop(call_stack_bindings);
167
+
168
+ // Evaluate each of the matching breakpoint
169
+ for (i = 0; i < matching_breakpoints_len; i++) {
170
+ matching_breakpoint = c_matching_breakpoints[i];
171
+ rb_funcall(self, rb_intern("eval_breakpoint"), 2, matching_breakpoint, call_stack_bindings);
172
+ }
173
+
174
+ return;
175
+ }
176
+
177
+ /**
178
+ * disable_line_trace_for_thread
179
+ * Turn off line event trace hook for a given thread. If no thread is given, it
180
+ * turns off line event trace hook in current thread. It only takes action if
181
+ * the thread has a thread variable "gcloud_line_trace_set" that's true.
182
+ */
183
+ static VALUE
184
+ disable_line_trace_for_thread(VALUE thread)
185
+ {
186
+ VALUE thread_variables_hash;
187
+ VALUE line_trace_set;
188
+
189
+ if (!RTEST(thread)) {
190
+ thread = rb_thread_current();
191
+ }
192
+ thread_variables_hash = rb_ivar_get(thread, rb_intern("locals"));
193
+ line_trace_set = rb_hash_aref(thread_variables_hash, rb_str_new2("gcloud_line_trace_set"));
194
+
195
+ if (RTEST(line_trace_set)) {
196
+ rb_thread_remove_event_hook(thread, line_trace_callback);
197
+ rb_hash_aset(thread_variables_hash, rb_str_new2("gcloud_line_trace_set"), Qfalse);
198
+ }
199
+
200
+ return Qnil;
201
+ }
202
+
203
+ /**
204
+ * enable_line_trace_for_thread
205
+ * Turn on line even trace for current thread. Also set a flag
206
+ * "gcloud_line_trace_set" to Qtrue in current thread's thread variable.
207
+ */
208
+ static VALUE
209
+ enable_line_trace_for_thread(VALUE self)
210
+ {
211
+ VALUE current_thread = rb_thread_current();
212
+ VALUE thread_variables_hash = rb_ivar_get(current_thread, rb_intern("locals"));
213
+ VALUE line_trace_set = rb_hash_aref(thread_variables_hash, rb_str_new2("gcloud_line_trace_set"));
214
+
215
+ if (!RTEST(line_trace_set)) {
216
+ rb_thread_add_event_hook(current_thread, line_trace_callback, RUBY_EVENT_LINE, self);
217
+ rb_hash_aset(thread_variables_hash, rb_str_new2("gcloud_line_trace_set"), Qtrue);
218
+ }
219
+
220
+ return Qnil;
221
+ }
222
+
223
+ /**
224
+ * return_trace_callback
225
+ * Callback function for tracer#return_tracepoint. It gets called on
226
+ * RUBY_EVENT_END, RUBY_EVENT_RETURN, RUBY_EVENT_C_RETURN, and
227
+ * RUBY_EVENT_B_RETURN events. It keeps line tracing consistent when Ruby
228
+ * program counter interleaves files. Everytime called, it checks caller stack
229
+ * frame's file path, if it matches any of the breakpoints, it turns line
230
+ * event tracing back on. It also decrements tracer#return_tracepoint_counter
231
+ * everytime called. When the counter is at 0, it disables itself, which should
232
+ * be the same stack frame that the return_tracepoint is turned on.
233
+ */
234
+ static void
235
+ return_trace_callback(void *data, rb_trace_arg_t *trace_arg)
236
+ {
237
+ VALUE match_found;
238
+ VALUE self = (VALUE) data;
239
+ VALUE caller_locations = rb_funcall(rb_mKernel, rb_intern("caller_locations"), 2, INT2NUM(0), INT2NUM(1));
240
+ VALUE *c_caller_locations;
241
+ VALUE caller_location;
242
+ VALUE caller_path;
243
+
244
+ if(!RTEST(caller_locations)) {
245
+ return;
246
+ }
247
+
248
+ c_caller_locations = RARRAY_PTR(caller_locations);
249
+ caller_location = c_caller_locations[0];
250
+ caller_path = rb_funcall(caller_location, rb_intern("absolute_path"), 0);
251
+
252
+ if(!RTEST(caller_path)) {
253
+ return;
254
+ }
255
+
256
+ match_found = match_breakpoints_files(self, caller_path);
257
+
258
+ if (match_found) {
259
+ enable_line_trace_for_thread(self);
260
+ }
261
+
262
+ return;
263
+ }
264
+
265
+ /**
266
+ * disable_return_trace_for_thread
267
+ * Turn off return events trace hook for a given thread. If no thread is given, it
268
+ * turns off line event trace hook in current thread. It only takes action if
269
+ * the thread has a thread variable "gcloud_return_trace_set" that's true.
270
+ */
271
+ static VALUE
272
+ disable_return_trace_for_thread(VALUE thread)
273
+ {
274
+ VALUE thread_variables_hash;
275
+ VALUE return_trace_set;
276
+
277
+ if (!RTEST(thread)) {
278
+ thread = rb_thread_current();
279
+ }
280
+ thread_variables_hash = rb_ivar_get(thread, rb_intern("locals"));
281
+ return_trace_set = rb_hash_aref(thread_variables_hash, rb_str_new2("gcloud_return_trace_set"));
282
+
283
+ if (RTEST(return_trace_set)) {
284
+ rb_thread_remove_event_hook(thread, (rb_event_hook_func_t)return_trace_callback);
285
+ rb_hash_aset(thread_variables_hash, rb_str_new2("gcloud_return_trace_set"), Qfalse);
286
+ }
287
+
288
+ return Qnil;
289
+ }
290
+
291
+ /**
292
+ * enable_return_trace_for_thread
293
+ * Turn on return events trace for current thread. Also set a flag
294
+ * "gcloud_return_trace_set" to Qtrue in current thread's thread variable.
295
+ */
296
+ static VALUE
297
+ enable_return_trace_for_thread(VALUE self)
298
+ {
299
+ VALUE current_thread = rb_thread_current();
300
+ VALUE thread_variables_hash = rb_ivar_get(current_thread, rb_intern("locals"));
301
+ VALUE return_trace_set = rb_hash_aref(thread_variables_hash, rb_str_new2("gcloud_return_trace_set"));
302
+
303
+ if (!RTEST(return_trace_set)) {
304
+ int return_tracepoint_event = RUBY_EVENT_END | RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN;
305
+ rb_thread_add_event_hook2(current_thread, (rb_event_hook_func_t)return_trace_callback, return_tracepoint_event, self, RUBY_EVENT_HOOK_FLAG_RAW_ARG | RUBY_EVENT_HOOK_FLAG_SAFE);
306
+ rb_hash_aset(thread_variables_hash, rb_str_new2("gcloud_return_trace_set"), Qtrue);
307
+ }
308
+
309
+ return Qnil;
310
+ }
311
+
312
+ /**
313
+ * file_tracepoint_callback
314
+ * Callback function for tracer#file_tracepoint. It gets called on
315
+ * RUBY_EVENT_CLASS, RUBY_EVENT_CALL, RUBY_EVENT_C_CALL, and RUBY_EVENT_B_CALL
316
+ * events. It check if any breakpoints matches current file the VM program counter
317
+ * is in, and turn on line event tracing for that thread. Otherwise turn off
318
+ * line tracing if in wrong file. The first time it turns on line even tracing,
319
+ * it also turns on tracer#return_tracepoint to maintain line tracing
320
+ * consistency when file execution interleaves. If return_tracepoint is already
321
+ * on, it increments tracer#return_tracepoint_counter.
322
+ */
323
+ static void
324
+ file_tracepoint_callback(VALUE tracepoint, void *data)
325
+ {
326
+ VALUE self = (VALUE) data;
327
+ rb_trace_arg_t *tracepoint_arg = rb_tracearg_from_tracepoint(tracepoint);
328
+ VALUE tracepoint_path = rb_tracearg_path(tracepoint_arg);
329
+ VALUE match_found;
330
+
331
+ if (!RB_TYPE_P(tracepoint_path, T_STRING))
332
+ return;
333
+
334
+ match_found = match_breakpoints_files(self, tracepoint_path);
335
+
336
+ if (match_found) {
337
+ enable_line_trace_for_thread(self);
338
+ enable_return_trace_for_thread(self);
339
+ }
340
+ else {
341
+ disable_line_trace_for_thread(Qnil);
342
+ }
343
+
344
+ return;
345
+ }
346
+
347
+ #ifdef RUBY_EVENT_FIBER_SWITCH
348
+ static void
349
+ fiber_tracepoint_callback(VALUE tracepoint, void *data)
350
+ {
351
+ VALUE self = (VALUE) data;
352
+ rb_trace_arg_t *tracepoint_arg = rb_tracearg_from_tracepoint(tracepoint);
353
+ VALUE tracepoint_lineno = rb_tracearg_lineno(tracepoint_arg);
354
+ int c_tracepoint_lineno = NUM2INT(tracepoint_lineno);
355
+
356
+ // Only if lineno is greater than 0, then we know this event is triggered from
357
+ // fiber execution, and we blindly starts line_trace.
358
+ if (c_tracepoint_lineno > 0) {
359
+ enable_line_trace_for_thread(self);
360
+ }
361
+
362
+ return;
363
+ }
364
+ #endif
365
+
366
+ /**
367
+ * register_tracepoint
368
+ * Helper function to create a new tracepoint and set the instance varaible on
369
+ * tracer if it doesn't exist already. Returns the existing tracepoint or the
370
+ * newly created tracepoint.
371
+ */
372
+ static VALUE
373
+ register_tracepoint(VALUE self, int event, const char *instance_variable_name, void (*call_back_func)(VALUE, void *))
374
+ {
375
+ VALUE tracepoint = rb_iv_get(self, instance_variable_name);
376
+
377
+ if (event && !RTEST(tracepoint)) {
378
+ tracepoint = rb_tracepoint_new(Qnil, event, call_back_func, (void *)self);
379
+ rb_iv_set(self, instance_variable_name, tracepoint);
380
+ }
381
+
382
+ return tracepoint;
383
+ }
384
+
385
+ /**
386
+ * rb_disable_traces
387
+ * This is implmenetation of Tracer#disable_traces methods. It disables
388
+ * tracer#file_tracepoint, tracer#fiber_tracepoint, return even tracing, and
389
+ * line event tracing for all threads.
390
+ */
391
+ static VALUE
392
+ rb_disable_traces(VALUE self)
393
+ {
394
+ VALUE file_tracepoint;
395
+ VALUE fiber_tracepoint;
396
+ VALUE threads;
397
+ VALUE *c_threads;
398
+ int c_threads_len;
399
+ VALUE thread;
400
+ int i;
401
+
402
+ file_tracepoint = rb_iv_get(self, "@file_tracepoint");
403
+ threads = rb_funcall(rb_cThread, rb_intern("list"), 0);
404
+ c_threads_len = RARRAY_LEN(threads);
405
+ c_threads = RARRAY_PTR(threads);
406
+ UNUSED(fiber_tracepoint);
407
+
408
+ if (RTEST(file_tracepoint) && RTEST(rb_tracepoint_enabled_p(file_tracepoint)))
409
+ rb_tracepoint_disable(file_tracepoint);
410
+
411
+ #ifdef RUBY_EVENT_FIBER_SWITCH
412
+ fiber_tracepoint= rb_iv_get(self, "@fiber_tracepoint");
413
+ if (RTEST(fiber_tracepoint) && RTEST(rb_tracepoint_enabled_p(fiber_tracepoint)))
414
+ rb_tracepoint_disable(fiber_tracepoint);
415
+ #endif
416
+
417
+ for (i = 0; i < c_threads_len; i++) {
418
+ thread = c_threads[i];
419
+ if (RTEST(rb_funcall(thread, rb_intern("alive?"), 0))) {
420
+ disable_line_trace_for_thread(thread);
421
+ disable_return_trace_for_thread(thread);
422
+ }
423
+ }
424
+
425
+ return Qnil;
426
+ }
427
+
428
+ /**
429
+ * rb_enable_traces
430
+ * This is the implementation of Tracer#enable_traces methods. It creates
431
+ * the tracer#file_tracepoints and tracer#fiber_tracepoints for the first time
432
+ * called. Then it also enables them immediately upon creation.
433
+ */
434
+ static VALUE
435
+ rb_enable_traces(VALUE self)
436
+ {
437
+ VALUE file_tracepoint;
438
+ VALUE fiber_tracepoint;
439
+
440
+ file_tracepoint = register_tracepoint(self, FILE_TRACEPOINT_EVENT, "@file_tracepoint", file_tracepoint_callback);
441
+ UNUSED(fiber_tracepoint);
442
+
443
+ // Immediately activate file tracepoint and fiber tracepoint
444
+ if (RTEST(file_tracepoint) && !RTEST(rb_tracepoint_enabled_p(file_tracepoint))) {
445
+ rb_tracepoint_enable(file_tracepoint);
446
+ }
447
+ #ifdef RUBY_EVENT_FIBER_SWITCH
448
+ fiber_tracepoint = register_tracepoint(self, RUBY_EVENT_FIBER_SWITCH, "@fiber_tracepoint", fiber_tracepoint_callback);
449
+ if (RTEST(fiber_tracepoint) && !RTEST(rb_tracepoint_enabled_p(fiber_tracepoint))) {
450
+ rb_tracepoint_enable(fiber_tracepoint);
451
+ }
452
+ #endif
453
+ return Qnil;
454
+ }
455
+
456
+ /**
457
+ * rb_disable_traces_for_thread
458
+ * It disables line tracing and return event tracing for current thread.
459
+ */
460
+ static VALUE
461
+ rb_disable_traces_for_thread(VALUE self)
462
+ {
463
+ VALUE thread = rb_thread_current();
464
+ disable_line_trace_for_thread(thread);
465
+ disable_return_trace_for_thread(thread);
466
+
467
+ return Qnil;
468
+ }
469
+
470
+ void
471
+ Init_tracer(VALUE mDebugger)
472
+ {
473
+ VALUE cTracer = rb_define_class_under(mDebugger, "Tracer", rb_cObject);
474
+
475
+ rb_define_method(cTracer, "enable_traces", rb_enable_traces, 0);
476
+ rb_define_method(cTracer, "disable_traces", rb_disable_traces, 0);
477
+ rb_define_method(cTracer, "disable_traces_for_thread", rb_disable_traces_for_thread, 0);
478
+ }