Ptrace 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +6 -0
- data/LICENSE +674 -0
- data/README +105 -0
- data/examples/kill.rb +14 -0
- data/examples/peekpoke.rb +53 -0
- data/examples/regs.rb +47 -0
- data/examples/syscall.rb +33 -0
- data/lib/Ptrace.rb +571 -0
- data/module/Ptrace.c +683 -0
- data/module/Ptrace.h +51 -0
- data/module/extconf.rb +11 -0
- data/module/rdoc_input/Ptrace_ext.rb +120 -0
- data/module/ruby_compat.c +17 -0
- data/module/ruby_compat.h +28 -0
- data/tests/ut_ptrace.rb +597 -0
- metadata +83 -0
data/module/Ptrace.c
ADDED
@@ -0,0 +1,683 @@
|
|
1
|
+
/* Ptrace.c
|
2
|
+
* Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
|
3
|
+
* Written by TG Community Developers <community@thoughtgang.org>
|
4
|
+
* Released under the GNU Public License, version 3.
|
5
|
+
* See http://www.gnu.org/licenses/gpl.txt for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
#include <signal.h>
|
10
|
+
#include <errno.h>
|
11
|
+
|
12
|
+
#include <sys/types.h>
|
13
|
+
#include <sys/ptrace.h>
|
14
|
+
#include <sys/user.h>
|
15
|
+
|
16
|
+
// TODO: how to represent a 128-bit number in C and ruby
|
17
|
+
// gcc: unsigned __int128
|
18
|
+
// BigDecimal.new("0.0001")
|
19
|
+
// require 'bigdecimal'
|
20
|
+
|
21
|
+
#include <ruby.h>
|
22
|
+
#include "ruby_compat.h"
|
23
|
+
|
24
|
+
#include "Ptrace.h"
|
25
|
+
|
26
|
+
#define IVAR(attr) "@" attr
|
27
|
+
|
28
|
+
// TODO: decode user data structure ala sys/user.h
|
29
|
+
|
30
|
+
static VALUE modPtrace;
|
31
|
+
static VALUE clsDebug;
|
32
|
+
static VALUE clsError;
|
33
|
+
|
34
|
+
|
35
|
+
static VALUE str_to_sym( const char * str ) {
|
36
|
+
VALUE var = rb_str_new_cstr(str);
|
37
|
+
return rb_funcall(var, rb_intern("to_sym"), 0);
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE pid_to_num( pid_t pid ) {
|
41
|
+
return (sizeof(pid_t) == sizeof(unsigned int)) ? UINT2NUM(pid)
|
42
|
+
: ULL2NUM(pid);
|
43
|
+
}
|
44
|
+
|
45
|
+
static pid_t num_to_pid( VALUE num ) {
|
46
|
+
if ( num == Qnil ) {
|
47
|
+
return 0;
|
48
|
+
}
|
49
|
+
|
50
|
+
return (sizeof(pid_t) == sizeof(unsigned int)) ? (pid_t) NUM2UINT(num)
|
51
|
+
: (pid_t) NUM2ULL(num);
|
52
|
+
}
|
53
|
+
|
54
|
+
/* return value for key or 0 */
|
55
|
+
static VALUE hash_get_int( VALUE h, VALUE key ) {
|
56
|
+
|
57
|
+
VALUE v = rb_hash_aref( h, key );
|
58
|
+
return (v == Qnil) ? UINT2NUM(0) : v;
|
59
|
+
}
|
60
|
+
|
61
|
+
#define CMD_HASH_ADD(h, str, val) \
|
62
|
+
rb_hash_aset(h, str_to_sym(str), UINT2NUM(val));
|
63
|
+
|
64
|
+
static VALUE build_cmd_hash( VALUE cls ) {
|
65
|
+
VALUE h = rb_hash_new();
|
66
|
+
|
67
|
+
CMD_HASH_ADD(h, SZ_PTRACE_TRACEME, PT_TRACE_ME)
|
68
|
+
CMD_HASH_ADD(h, SZ_PTRACE_PEEKTEXT, PT_READ_I)
|
69
|
+
CMD_HASH_ADD(h, SZ_PTRACE_PEEKDATA, PT_READ_D)
|
70
|
+
CMD_HASH_ADD(h, SZ_PTRACE_POKETEXT, PT_WRITE_I)
|
71
|
+
CMD_HASH_ADD(h, SZ_PTRACE_POKEDATA, PT_WRITE_D)
|
72
|
+
CMD_HASH_ADD(h, SZ_PTRACE_CONT, PT_CONTINUE)
|
73
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SINGLESTEP, PT_STEP)
|
74
|
+
CMD_HASH_ADD(h, SZ_PTRACE_KILL, PT_KILL)
|
75
|
+
CMD_HASH_ADD(h, SZ_PTRACE_ATTACH, PT_ATTACH)
|
76
|
+
CMD_HASH_ADD(h, SZ_PTRACE_DETACH, PT_DETACH)
|
77
|
+
|
78
|
+
/* ====================================================== */
|
79
|
+
/* These may not be present in all ptrace implementations */
|
80
|
+
#ifdef PT_WRITE_U
|
81
|
+
CMD_HASH_ADD(h, SZ_PTRACE_POKEUSR, PT_WRITE_U)
|
82
|
+
#endif
|
83
|
+
#ifdef PT_READ_U
|
84
|
+
CMD_HASH_ADD(h, SZ_PTRACE_PEEKUSR, PT_READ_U)
|
85
|
+
#endif
|
86
|
+
#ifdef PT_SYSCALL
|
87
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SYSCALL, PT_SYSCALL)
|
88
|
+
#endif
|
89
|
+
#ifdef PT_GETREGS
|
90
|
+
CMD_HASH_ADD(h, SZ_PTRACE_GETREGS, PT_GETREGS)
|
91
|
+
#endif
|
92
|
+
#ifdef PT_GETFPREGS
|
93
|
+
CMD_HASH_ADD(h, SZ_PTRACE_GETFPREGS, PT_GETFPREGS)
|
94
|
+
#endif
|
95
|
+
#ifdef PT_GETFPXREGS
|
96
|
+
CMD_HASH_ADD(h, SZ_PTRACE_GETFPXREGS, PT_GETFPXREGS)
|
97
|
+
#endif
|
98
|
+
#ifdef PT_SETREGS
|
99
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SETREGS, PT_SETREGS)
|
100
|
+
#endif
|
101
|
+
#ifdef PT_SETFPREGS
|
102
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SETFPREGS, PT_SETFPREGS)
|
103
|
+
#endif
|
104
|
+
#ifdef PT_SETFPXREGS
|
105
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SETFPXREGS, PT_SETFPXREGS)
|
106
|
+
#endif
|
107
|
+
#ifdef PT_SETOPTIONS
|
108
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SETOPTIONS, PT_SETOPTIONS)
|
109
|
+
#endif
|
110
|
+
#ifdef PT_GETSIGINFO
|
111
|
+
CMD_HASH_ADD(h, SZ_PTRACE_GETSIGINFO, PT_GETSIGINFO)
|
112
|
+
#endif
|
113
|
+
#ifdef PT_SETSIGINFO
|
114
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SETSIGINFO, PT_SETSIGINFO)
|
115
|
+
#endif
|
116
|
+
#ifdef PT_GETEVENTMSG
|
117
|
+
CMD_HASH_ADD(h, SZ_PTRACE_GETEVENTMSG, PT_GETEVENTMSG)
|
118
|
+
#endif
|
119
|
+
#ifdef PT_SYSEMU
|
120
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SYSEMU, PT_SYSEMU)
|
121
|
+
#endif
|
122
|
+
#ifdef PT_SYSEMU_SINGLESTEP
|
123
|
+
CMD_HASH_ADD(h, SZ_PTRACE_SYSEMU_SINGLESTEP, PT_SYSEMU_SINGLESTEP)
|
124
|
+
#endif
|
125
|
+
/* ====================================================== */
|
126
|
+
|
127
|
+
return h;
|
128
|
+
}
|
129
|
+
|
130
|
+
/* This is a hash of user structure members to offsets */
|
131
|
+
static VALUE build_user_hash( void ) {
|
132
|
+
VALUE h = rb_hash_new();
|
133
|
+
unsigned int offset;
|
134
|
+
|
135
|
+
//u_fp_valid
|
136
|
+
offset = sizeof(struct user_regs_struct);
|
137
|
+
//u_tsize =
|
138
|
+
offset += sizeof(int) + sizeof(struct user_fpregs_struct);
|
139
|
+
//u_dsize =
|
140
|
+
offset += sizeof(unsigned long int);
|
141
|
+
//u_ssize =
|
142
|
+
offset += sizeof(unsigned long int);
|
143
|
+
//start_code =
|
144
|
+
offset += sizeof(unsigned long int);
|
145
|
+
//start_stack =
|
146
|
+
offset += sizeof(unsigned long);
|
147
|
+
//signal =
|
148
|
+
offset += sizeof(unsigned long);
|
149
|
+
// magic
|
150
|
+
offset += sizeof(long int) + sizeof(void *) + sizeof(void *);
|
151
|
+
// comm
|
152
|
+
offset += sizeof(unsigned long int);
|
153
|
+
// debug_r0 - r7
|
154
|
+
offset += sizeof(char) * 32;
|
155
|
+
offset += sizeof(int);
|
156
|
+
//CMD_HASH_ADD(h, SZ_PTRACE_TRACEME, PT_TRACE_ME)
|
157
|
+
|
158
|
+
return h;
|
159
|
+
}
|
160
|
+
|
161
|
+
static VALUE build_option_hash( void ) {
|
162
|
+
VALUE h = rb_hash_new();
|
163
|
+
|
164
|
+
// TODO : Change this to if linux as these are not #defines!
|
165
|
+
#ifdef PTRACE_O_TRACESYSGOOD
|
166
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACESYSGOOD, PTRACE_O_TRACESYSGOOD)
|
167
|
+
#endif
|
168
|
+
#ifdef PTRACE_O_TRACEFORK
|
169
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACEFORK, PTRACE_O_TRACEFORK)
|
170
|
+
#endif
|
171
|
+
#ifdef PTRACE_O_TRACEVFORK
|
172
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACEVFORK, PTRACE_O_TRACEVFORK)
|
173
|
+
#endif
|
174
|
+
#ifdef PTRACE_O_TRACEVFORKDONE
|
175
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACEVFORKDONE, PTRACE_O_TRACEVFORKDONE)
|
176
|
+
#endif
|
177
|
+
#ifdef PTRACE_O_TRACECLONE
|
178
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACECLONE, PTRACE_O_TRACECLONE)
|
179
|
+
#endif
|
180
|
+
#ifdef PTRACE_O_TRACEEXEC
|
181
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACEEXEC, PTRACE_O_TRACEEXEC)
|
182
|
+
#endif
|
183
|
+
#ifdef PTRACE_O_TRACEEXIT
|
184
|
+
CMD_HASH_ADD(h, SZ_PTRACE_O_TRACEEXIT, PTRACE_O_TRACEEXIT)
|
185
|
+
#endif
|
186
|
+
return h;
|
187
|
+
}
|
188
|
+
|
189
|
+
/* ---------------------------------------------------------------------- */
|
190
|
+
|
191
|
+
static long int_ptrace_raw( enum __ptrace_request req, VALUE pid, void * addr,
|
192
|
+
void * data ) {
|
193
|
+
pid_t tgt;
|
194
|
+
long rv;
|
195
|
+
|
196
|
+
tgt = num_to_pid(pid);
|
197
|
+
rv = ptrace(req, tgt, addr, data);
|
198
|
+
if ( rv == -1l ) {
|
199
|
+
rb_raise(rb_eRuntimeError, "PTRACE: %s", strerror(errno));
|
200
|
+
}
|
201
|
+
|
202
|
+
return rv;
|
203
|
+
}
|
204
|
+
|
205
|
+
/* internal wrapper for ptrace that converts PID to a pid_t, and converts
|
206
|
+
* return value to a Fixnum */
|
207
|
+
static VALUE int_ptrace( enum __ptrace_request req, VALUE pid, void * addr,
|
208
|
+
void * data ) {
|
209
|
+
long rv = int_ptrace_raw(req, pid, addr, data);
|
210
|
+
return LONG2NUM(rv);
|
211
|
+
}
|
212
|
+
|
213
|
+
static VALUE int_ptrace_data( VALUE req, VALUE pid, VALUE addr, void * data ) {
|
214
|
+
enum __ptrace_request cmd = (req == Qnil) ? 0 :
|
215
|
+
(enum __ptrace_request) NUM2UINT(req);
|
216
|
+
void * tgt_addr = (addr == Qnil) ? NULL : (void *) NUM2OFFT(addr);
|
217
|
+
|
218
|
+
return int_ptrace(cmd, pid, tgt_addr, data);
|
219
|
+
}
|
220
|
+
|
221
|
+
|
222
|
+
/* ---------------------------------------------------------------------- */
|
223
|
+
/* PTRACE API */
|
224
|
+
|
225
|
+
static VALUE ptrace_send( VALUE cls, VALUE req, VALUE pid, VALUE addr) {
|
226
|
+
return int_ptrace_data( req, pid, addr, NULL );
|
227
|
+
}
|
228
|
+
|
229
|
+
/* NOTE only use this for data that is NOT a memory address (pointer)! */
|
230
|
+
static VALUE ptrace_send_data( VALUE cls, VALUE req, VALUE pid, VALUE addr,
|
231
|
+
VALUE data ) {
|
232
|
+
void * the_data = (data == Qnil) ? NULL : (void *) NUM2ULONG(data);
|
233
|
+
|
234
|
+
return int_ptrace_data(req, pid, addr, the_data);
|
235
|
+
}
|
236
|
+
|
237
|
+
/* peek_text, peek_data, peek_user */
|
238
|
+
static VALUE ptrace_peek( VALUE cls, VALUE req, VALUE pid, VALUE addr ) {
|
239
|
+
return int_ptrace_data(req, pid, addr, NULL);
|
240
|
+
}
|
241
|
+
|
242
|
+
/* poke_text, poke_data, poke_user */
|
243
|
+
static VALUE ptrace_poke( VALUE cls, VALUE req, VALUE pid, VALUE addr,
|
244
|
+
VALUE data ) {
|
245
|
+
void * the_data = (void *) NUM2ULONG(data);
|
246
|
+
|
247
|
+
return int_ptrace_data(req, pid, addr, the_data);
|
248
|
+
}
|
249
|
+
|
250
|
+
static VALUE ptrace_get_regs( VALUE cls, VALUE pid ) {
|
251
|
+
VALUE h = rb_hash_new();
|
252
|
+
|
253
|
+
#ifdef __linux
|
254
|
+
long rv = 0;
|
255
|
+
struct user_regs_struct regs = {0};
|
256
|
+
|
257
|
+
rv = int_ptrace_raw( PT_GETREGS, pid, NULL, ®s);
|
258
|
+
|
259
|
+
# ifdef __x86_64__
|
260
|
+
rb_hash_aset( h, rb_str_new_cstr("r15"), ULONG2NUM(regs.r15) );
|
261
|
+
rb_hash_aset( h, rb_str_new_cstr("r14"), ULONG2NUM(regs.r14) );
|
262
|
+
rb_hash_aset( h, rb_str_new_cstr("r13"), ULONG2NUM(regs.r13) );
|
263
|
+
rb_hash_aset( h, rb_str_new_cstr("r12"), ULONG2NUM(regs.r12) );
|
264
|
+
rb_hash_aset( h, rb_str_new_cstr("rbp"), ULONG2NUM(regs.rbp) );
|
265
|
+
rb_hash_aset( h, rb_str_new_cstr("rbx"), ULONG2NUM(regs.rbx) );
|
266
|
+
rb_hash_aset( h, rb_str_new_cstr("r11"), ULONG2NUM(regs.r11) );
|
267
|
+
rb_hash_aset( h, rb_str_new_cstr("r10"), ULONG2NUM(regs.r10) );
|
268
|
+
rb_hash_aset( h, rb_str_new_cstr("r9"), ULONG2NUM(regs.r9) );
|
269
|
+
rb_hash_aset( h, rb_str_new_cstr("r8"), ULONG2NUM(regs.r8) );
|
270
|
+
rb_hash_aset( h, rb_str_new_cstr("rax"), ULONG2NUM(regs.rax) );
|
271
|
+
rb_hash_aset( h, rb_str_new_cstr("rcx"), ULONG2NUM(regs.rcx) );
|
272
|
+
rb_hash_aset( h, rb_str_new_cstr("rdx"), ULONG2NUM(regs.rdx) );
|
273
|
+
rb_hash_aset( h, rb_str_new_cstr("rsi"), ULONG2NUM(regs.rsi) );
|
274
|
+
rb_hash_aset( h, rb_str_new_cstr("rdi"), ULONG2NUM(regs.rdi) );
|
275
|
+
rb_hash_aset( h, rb_str_new_cstr("orig_rax"), ULONG2NUM(regs.orig_rax));
|
276
|
+
rb_hash_aset( h, rb_str_new_cstr("rip"), ULONG2NUM(regs.rip) );
|
277
|
+
rb_hash_aset( h, rb_str_new_cstr("cs"), ULONG2NUM(regs.cs) );
|
278
|
+
rb_hash_aset( h, rb_str_new_cstr("eflags"), ULONG2NUM(regs.eflags) );
|
279
|
+
rb_hash_aset( h, rb_str_new_cstr("rsp"), ULONG2NUM(regs.rsp) );
|
280
|
+
rb_hash_aset( h, rb_str_new_cstr("ss"), ULONG2NUM(regs.ss) );
|
281
|
+
rb_hash_aset( h, rb_str_new_cstr("fs_base"), ULONG2NUM(regs.fs_base) );
|
282
|
+
rb_hash_aset( h, rb_str_new_cstr("gs_base"), ULONG2NUM(regs.gs_base) );
|
283
|
+
rb_hash_aset( h, rb_str_new_cstr("ds"), ULONG2NUM(regs.ds) );
|
284
|
+
rb_hash_aset( h, rb_str_new_cstr("es"), ULONG2NUM(regs.es) );
|
285
|
+
rb_hash_aset( h, rb_str_new_cstr("fs"), ULONG2NUM(regs.fs) );
|
286
|
+
rb_hash_aset( h, rb_str_new_cstr("gs"), ULONG2NUM(regs.gs) );
|
287
|
+
# else
|
288
|
+
rb_hash_aset( h, rb_str_new_cstr("ebx"), ULONG2NUM(regs.ebx) );
|
289
|
+
rb_hash_aset( h, rb_str_new_cstr("ecx"), ULONG2NUM(regs.ecx) );
|
290
|
+
rb_hash_aset( h, rb_str_new_cstr("edx"), ULONG2NUM(regs.edx) );
|
291
|
+
rb_hash_aset( h, rb_str_new_cstr("esi"), ULONG2NUM(regs.esi) );
|
292
|
+
rb_hash_aset( h, rb_str_new_cstr("edi"), ULONG2NUM(regs.edi) );
|
293
|
+
rb_hash_aset( h, rb_str_new_cstr("ebp"), ULONG2NUM(regs.ebp) );
|
294
|
+
rb_hash_aset( h, rb_str_new_cstr("eax"), ULONG2NUM(regs.eax) );
|
295
|
+
rb_hash_aset( h, rb_str_new_cstr("ds"), ULONG2NUM(regs.xds) );
|
296
|
+
rb_hash_aset( h, rb_str_new_cstr("es"), ULONG2NUM(regs.xes) );
|
297
|
+
rb_hash_aset( h, rb_str_new_cstr("fs"), ULONG2NUM(regs.xfs) );
|
298
|
+
rb_hash_aset( h, rb_str_new_cstr("gs"), ULONG2NUM(regs.xgs) );
|
299
|
+
rb_hash_aset( h, rb_str_new_cstr("orig_eax"), ULONG2NUM(regs.orig_eax));
|
300
|
+
rb_hash_aset( h, rb_str_new_cstr("eip"), ULONG2NUM(regs.eip) );
|
301
|
+
rb_hash_aset( h, rb_str_new_cstr("cs"), ULONG2NUM(regs.xcs) );
|
302
|
+
rb_hash_aset( h, rb_str_new_cstr("eflags"), ULONG2NUM(regs.eflags) );
|
303
|
+
rb_hash_aset( h, rb_str_new_cstr("esp"), ULONG2NUM(regs.esp) );
|
304
|
+
rb_hash_aset( h, rb_str_new_cstr("ss"), ULONG2NUM(regs.xss) );
|
305
|
+
# endif
|
306
|
+
#endif
|
307
|
+
return h;
|
308
|
+
}
|
309
|
+
|
310
|
+
static VALUE ptrace_set_regs( VALUE cls, VALUE pid, VALUE h ) {
|
311
|
+
|
312
|
+
#ifdef __linux
|
313
|
+
long rv = 0;
|
314
|
+
struct user_regs_struct regs = {0};
|
315
|
+
int_ptrace_raw( PT_GETREGS, pid, NULL, ®s);
|
316
|
+
|
317
|
+
# ifdef __x86_64__
|
318
|
+
regs.r15 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r15") ));
|
319
|
+
regs.r14 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r14") ));
|
320
|
+
regs.r13 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r13") ));
|
321
|
+
regs.r12 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r12") ));
|
322
|
+
regs.rbp = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rbp") ));
|
323
|
+
regs.rbx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rbx") ));
|
324
|
+
regs.r11 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r11") ));
|
325
|
+
regs.r10 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r10") ));
|
326
|
+
regs.r9 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r9") ));
|
327
|
+
regs.r8 = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("r8") ));
|
328
|
+
regs.rax = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rax") ));
|
329
|
+
regs.rcx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rcx") ));
|
330
|
+
regs.rdx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rdx") ));
|
331
|
+
regs.rsi = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rsi") ));
|
332
|
+
regs.rdi = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rdi") ));
|
333
|
+
/* Ptrace does not allow modification of these registers:
|
334
|
+
regs.orig_rax = NUM2ULONG(hash_get_int(h, rb_str_new_cstr("orig_rax")));
|
335
|
+
regs.cs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("cs") ));
|
336
|
+
regs.ss = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ss") ));
|
337
|
+
regs.fs_base = NUM2ULONG(hash_get_int(h, rb_str_new_cstr("fs_base") ));
|
338
|
+
regs.gs_base = NUM2ULONG(hash_get_int(h, rb_str_new_cstr("gs_base") ));
|
339
|
+
*/
|
340
|
+
regs.rip = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rip") ));
|
341
|
+
regs.eflags = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("eflags") ));
|
342
|
+
regs.rsp = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rsp") ));
|
343
|
+
regs.ds = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ds") ));
|
344
|
+
regs.es = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("es") ));
|
345
|
+
regs.fs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fs") ));
|
346
|
+
regs.gs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("gs") ));
|
347
|
+
# else
|
348
|
+
regs.ebx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ebx") ));
|
349
|
+
regs.ecx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ecx") ));
|
350
|
+
regs.edx = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("edx") ));
|
351
|
+
regs.esi = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("esi") ));
|
352
|
+
regs.edi = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("edi") ));
|
353
|
+
regs.ebp = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ebp") ));
|
354
|
+
regs.eax = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("eax") ));
|
355
|
+
regs.xds = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ds") ));
|
356
|
+
regs.xes = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("es") ));
|
357
|
+
regs.xfs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fs") ));
|
358
|
+
regs.xgs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("gs") ));
|
359
|
+
/* Ptrace does not allow modification of these registers:
|
360
|
+
regs.orig_rax = NUM2ULONG(hash_get_int(h, rb_str_new_cstr("orig_rax")));
|
361
|
+
regs.xcs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("cs") ));
|
362
|
+
regs.xss = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ss") ));
|
363
|
+
*/
|
364
|
+
regs.eip = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("eip") ));
|
365
|
+
regs.eflags = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("eflags") ));
|
366
|
+
regs.esp = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("esp") ));
|
367
|
+
# endif
|
368
|
+
rv = int_ptrace_raw( PT_SETREGS, pid, NULL, ®s);
|
369
|
+
#endif
|
370
|
+
return Qnil;
|
371
|
+
}
|
372
|
+
|
373
|
+
static VALUE ptrace_get_fpregs( VALUE cls, VALUE pid ) {
|
374
|
+
VALUE h = rb_hash_new();
|
375
|
+
#ifdef __linux
|
376
|
+
long rv = 0;
|
377
|
+
int i;
|
378
|
+
struct user_fpregs_struct regs = {0};
|
379
|
+
|
380
|
+
rv = int_ptrace_raw( PT_GETFPREGS, pid, NULL, ®s);
|
381
|
+
|
382
|
+
# ifdef __x86_64__
|
383
|
+
rb_hash_aset( h, rb_str_new_cstr("cwd"), UINT2NUM(regs.cwd) );
|
384
|
+
rb_hash_aset( h, rb_str_new_cstr("swd"), UINT2NUM(regs.swd) );
|
385
|
+
rb_hash_aset( h, rb_str_new_cstr("ftw"), UINT2NUM(regs.ftw) );
|
386
|
+
rb_hash_aset( h, rb_str_new_cstr("fop"), UINT2NUM(regs.fop) );
|
387
|
+
rb_hash_aset( h, rb_str_new_cstr("rip"), ULONG2NUM(regs.rip) );
|
388
|
+
rb_hash_aset( h, rb_str_new_cstr("rdp"), ULONG2NUM(regs.rdp) );
|
389
|
+
rb_hash_aset( h, rb_str_new_cstr("mxcsr"), UINT2NUM(regs.mxcsr) );
|
390
|
+
rb_hash_aset( h, rb_str_new_cstr("mxcr_mask"),
|
391
|
+
UINT2NUM(regs.mxcr_mask) );
|
392
|
+
for ( i = 0; i < 32; i++ ) {
|
393
|
+
char buf[8];
|
394
|
+
sprintf(buf, "ST(%d)", i);
|
395
|
+
// TODO: 8 x 16-byte regs
|
396
|
+
//rb_hash_aset( h, rb_str_new_cstr(buf),
|
397
|
+
// UINT2NUM(regs.st_space[i]) );
|
398
|
+
}
|
399
|
+
for ( i = 0; i < 64; i++ ) {
|
400
|
+
char buf[8];
|
401
|
+
sprintf(buf, "xmm%d", i);
|
402
|
+
// TODO: 16 x 16-byte regs
|
403
|
+
//rb_hash_aset( h, rb_str_new_cstr(buf),
|
404
|
+
// UINT2NUM(regs.xmm_space[i]) );
|
405
|
+
}
|
406
|
+
# else
|
407
|
+
rb_hash_aset( h, rb_str_new_cstr("cwd"), UINT2NUM(regs.cwd) );
|
408
|
+
rb_hash_aset( h, rb_str_new_cstr("swd"), UINT2NUM(regs.swd) );
|
409
|
+
rb_hash_aset( h, rb_str_new_cstr("twd"), UINT2NUM(regs.twd) );
|
410
|
+
rb_hash_aset( h, rb_str_new_cstr("fip"), UINT2NUM(regs.fip) );
|
411
|
+
rb_hash_aset( h, rb_str_new_cstr("fcs"), UINT2NUM(regs.fcs) );
|
412
|
+
rb_hash_aset( h, rb_str_new_cstr("foo"), UINT2NUM(regs.foo) );
|
413
|
+
rb_hash_aset( h, rb_str_new_cstr("fos"), UINT2NUM(regs.fos) );
|
414
|
+
for ( i = 0; i < 20; i++ ) {
|
415
|
+
// 20x long int st_space
|
416
|
+
char buf[8];
|
417
|
+
sprintf(buf, "ST(%d)", i);
|
418
|
+
// TODO: 8 x 16-byte regs
|
419
|
+
//rb_hash_aset( h, rb_str_new_cstr(buf),
|
420
|
+
// UINT2NUM(regs.st_space[i]) );
|
421
|
+
}
|
422
|
+
# endif
|
423
|
+
#elif defined(__APPLE__)
|
424
|
+
# ifdef __x86_64__
|
425
|
+
# else
|
426
|
+
# endif
|
427
|
+
#endif
|
428
|
+
return h;
|
429
|
+
}
|
430
|
+
|
431
|
+
static VALUE ptrace_set_fpregs( VALUE cls, VALUE pid, VALUE h ) {
|
432
|
+
|
433
|
+
#ifdef __linux
|
434
|
+
long rv = 0;
|
435
|
+
int i;
|
436
|
+
struct user_fpregs_struct regs = {0};
|
437
|
+
# ifdef __x86_64__
|
438
|
+
regs.cwd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("cwd") ));
|
439
|
+
regs.swd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("swd") ));
|
440
|
+
regs.ftw = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ftw") ));
|
441
|
+
regs.fop = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fop") ));
|
442
|
+
regs.rip = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rip") ));
|
443
|
+
regs.rdp = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("rdp") ));
|
444
|
+
regs.mxcsr = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("mxcsr") ));
|
445
|
+
regs.mxcr_mask = NUM2ULONG(hash_get_int( h,
|
446
|
+
rb_str_new_cstr("mxcr_mask") ));
|
447
|
+
for ( i = 0; i < 32; i++ ) {
|
448
|
+
char buf[8];
|
449
|
+
sprintf(buf, "ST(%d)", i);
|
450
|
+
// TODO: 8 * 16-byte regs
|
451
|
+
//regs.st_space[i] = NUM2UINT(hash_get_int( h,
|
452
|
+
// rb_str_new_cstr(buf) ));
|
453
|
+
}
|
454
|
+
for ( i = 0; i < 64; i++ ) {
|
455
|
+
char buf[8];
|
456
|
+
sprintf(buf, "xmm%d", i);
|
457
|
+
// TODO : 16 x 16-byte regs
|
458
|
+
//regs.xmm_space[i] = NUM2UINT(hash_get_int( h,
|
459
|
+
// rb_str_new_cstr(buf) ));
|
460
|
+
}
|
461
|
+
# else
|
462
|
+
regs.cwd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("cwd") ));
|
463
|
+
regs.swd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("swd") ));
|
464
|
+
regs.twd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("twd") ));
|
465
|
+
regs.fip = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fip") ));
|
466
|
+
regs.fcs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fcs") ));
|
467
|
+
regs.foo = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("foo") ));
|
468
|
+
regs.fos = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fos") ));
|
469
|
+
for ( i = 0; i < 20; i++ ) {
|
470
|
+
char buf[8];
|
471
|
+
sprintf(buf, "ST(%d)", i);
|
472
|
+
// TODO: 8 * 16-byte regs
|
473
|
+
//regs.st_space[i] = NUM2UINT(hash_get_int( h,
|
474
|
+
// rb_str_new_cstr(buf) ));
|
475
|
+
}
|
476
|
+
# endif
|
477
|
+
rv = int_ptrace_raw( PT_SETFPREGS, pid, NULL, ®s);
|
478
|
+
#elif defined(__APPLE__)
|
479
|
+
# ifdef __x86_64__
|
480
|
+
# else
|
481
|
+
# endif
|
482
|
+
#endif
|
483
|
+
return Qnil;
|
484
|
+
}
|
485
|
+
|
486
|
+
static VALUE ptrace_get_fpxregs( VALUE cls, VALUE pid ) {
|
487
|
+
VALUE h = rb_hash_new();
|
488
|
+
#ifdef __linux
|
489
|
+
long rv = 0;
|
490
|
+
int i;
|
491
|
+
|
492
|
+
# ifdef __x86_64__
|
493
|
+
// Nothing to do: x86-64 has no fpxregs structure
|
494
|
+
# else
|
495
|
+
struct user_fpxregs_struct regs = {0};
|
496
|
+
|
497
|
+
rv = int_ptrace_raw( PT_GETFPREGS, pid, NULL, ®s);
|
498
|
+
|
499
|
+
rb_hash_aset( h, rb_str_new_cstr("cwd"), UINT2NUM(regs.cwd) );
|
500
|
+
rb_hash_aset( h, rb_str_new_cstr("swd"), UINT2NUM(regs.swd) );
|
501
|
+
rb_hash_aset( h, rb_str_new_cstr("twd"), UINT2NUM(regs.twd) );
|
502
|
+
rb_hash_aset( h, rb_str_new_cstr("fop"), UINT2NUM(regs.fop) );
|
503
|
+
rb_hash_aset( h, rb_str_new_cstr("fip"), ULONG2NUM(regs.fip) );
|
504
|
+
rb_hash_aset( h, rb_str_new_cstr("fcs"), UINT2NUM(regs.fcs) );
|
505
|
+
rb_hash_aset( h, rb_str_new_cstr("foo"), UINT2NUM(regs.foo) );
|
506
|
+
rb_hash_aset( h, rb_str_new_cstr("fos"), UINT2NUM(regs.fos) );
|
507
|
+
rb_hash_aset( h, rb_str_new_cstr("mxcsr"), UINT2NUM(regs.mxcsr) );
|
508
|
+
for ( i = 0; i < 32; i++ ) {
|
509
|
+
char buf[8];
|
510
|
+
sprintf(buf, "ST(%d)", i);
|
511
|
+
// TODO: 8 x 16-byte regs
|
512
|
+
//rb_hash_aset( h, rb_str_new_cstr(buf),
|
513
|
+
// UINT2NUM(regs.st_space[i]) );
|
514
|
+
}
|
515
|
+
for ( i = 0; i < 32; i++ ) {
|
516
|
+
char buf[8];
|
517
|
+
sprintf(buf, "xmm%d", i);
|
518
|
+
// TODO: 16 x 16-byte regs
|
519
|
+
//rb_hash_aset( h, rb_str_new_cstr(buf),
|
520
|
+
// UINT2NUM(regs.xmm_space[i]) );
|
521
|
+
}
|
522
|
+
# endif
|
523
|
+
#elif defined(__APPLE__)
|
524
|
+
# ifdef __x86_64__
|
525
|
+
# else
|
526
|
+
# endif
|
527
|
+
#endif
|
528
|
+
return h;
|
529
|
+
}
|
530
|
+
|
531
|
+
static VALUE ptrace_set_fpxregs( VALUE cls, VALUE pid, VALUE h ) {
|
532
|
+
|
533
|
+
#ifdef __linux
|
534
|
+
long rv = 0;
|
535
|
+
int i;
|
536
|
+
# ifdef __x86_64__
|
537
|
+
// Nothing to do: x86-64 has no fpxregs structure
|
538
|
+
# else
|
539
|
+
struct user_fpxregs_struct regs = {0};
|
540
|
+
|
541
|
+
regs.cwd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("cwd") ));
|
542
|
+
regs.swd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("swd") ));
|
543
|
+
regs.twd = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("twd") ));
|
544
|
+
regs.fop = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fop") ));
|
545
|
+
regs.fip = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fip") ));
|
546
|
+
regs.fcs = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fcs") ));
|
547
|
+
regs.foo = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("foo") ));
|
548
|
+
regs.fos = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("fos") ));
|
549
|
+
regs.mxcsr = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("mxcsr") ));
|
550
|
+
for ( i = 0; i < 32; i++ ) {
|
551
|
+
char buf[8];
|
552
|
+
sprintf(buf, "ST(%d)", i);
|
553
|
+
// TODO: 8 * 16-byte regs
|
554
|
+
//regs.st_space[i] = NUM2UINT(hash_get_int( h,
|
555
|
+
// rb_str_new_cstr(buf) ));
|
556
|
+
}
|
557
|
+
for ( i = 0; i < 32; i++ ) {
|
558
|
+
char buf[8];
|
559
|
+
sprintf(buf, "xmm%d", i);
|
560
|
+
// TODO : 16 x 16-byte regs
|
561
|
+
//regs.xmm_space[i] = NUM2UINT(hash_get_int( h,
|
562
|
+
// rb_str_new_cstr(buf) ));
|
563
|
+
}
|
564
|
+
rv = int_ptrace_raw( PT_SETFPXREGS, pid, NULL, ®s);
|
565
|
+
# endif
|
566
|
+
#elif defined(__APPLE__)
|
567
|
+
# ifdef __x86_64__
|
568
|
+
# else
|
569
|
+
# endif
|
570
|
+
#endif
|
571
|
+
return Qnil;
|
572
|
+
}
|
573
|
+
|
574
|
+
static VALUE ptrace_get_siginfo( VALUE cls, VALUE pid ) {
|
575
|
+
VALUE h = rb_hash_new();
|
576
|
+
#ifdef PT_GETSIGINFO
|
577
|
+
# ifdef __linux
|
578
|
+
siginfo_t sig = {0};
|
579
|
+
|
580
|
+
int rv = int_ptrace_raw( PT_GETSIGINFO, pid, NULL, &sig);
|
581
|
+
|
582
|
+
rb_hash_aset( h, rb_str_new_cstr("signo"), UINT2NUM(sig.si_signo) );
|
583
|
+
rb_hash_aset( h, rb_str_new_cstr("errno"), UINT2NUM(sig.si_errno) );
|
584
|
+
rb_hash_aset( h, rb_str_new_cstr("code"), UINT2NUM(sig.si_code) );
|
585
|
+
//rb_hash_aset( h, rb_str_new_cstr("trapno"), UINT2NUM(sig.si_trapno) );
|
586
|
+
rb_hash_aset( h, rb_str_new_cstr("pid"), pid_to_num(sig.si_pid) );
|
587
|
+
rb_hash_aset( h, rb_str_new_cstr("uid"), UIDTNUM(sig.si_uid) );
|
588
|
+
rb_hash_aset( h, rb_str_new_cstr("status"), UINT2NUM(sig.si_status) );
|
589
|
+
rb_hash_aset( h, rb_str_new_cstr("utime"), UINT2NUM(sig.si_utime) );
|
590
|
+
rb_hash_aset( h, rb_str_new_cstr("stime"), UINT2NUM(sig.si_stime) );
|
591
|
+
//rb_hash_aset( h, rb_str_new_cstr("value"), UINT2NUM(sig.si_value) );
|
592
|
+
rb_hash_aset( h, rb_str_new_cstr("int"), UINT2NUM(sig.si_int) );
|
593
|
+
//rb_hash_aset( h, rb_str_new_cstr("ptr"), ULONG2NUM(sig.si_ptr) );
|
594
|
+
rb_hash_aset( h, rb_str_new_cstr("overrun"), UINT2NUM(sig.si_overrun) );
|
595
|
+
rb_hash_aset( h, rb_str_new_cstr("timerid"), UINT2NUM(sig.si_timerid) );
|
596
|
+
//rb_hash_aset( h, rb_str_new_cstr("addr"), ULONG2NUM(sig.si_addr) );
|
597
|
+
rb_hash_aset( h, rb_str_new_cstr("band"), UINT2NUM(sig.si_band) );
|
598
|
+
rb_hash_aset( h, rb_str_new_cstr("fd"), UINT2NUM(sig.si_fd) );
|
599
|
+
# elif defined(__APPLE__)
|
600
|
+
# endif
|
601
|
+
#endif
|
602
|
+
return h;
|
603
|
+
}
|
604
|
+
static VALUE ptrace_set_siginfo( VALUE cls, VALUE pid, VALUE hash ) {
|
605
|
+
VALUE rv = Qnil;
|
606
|
+
#ifdef PT_SET_SIGINFO
|
607
|
+
# ifdef __linux
|
608
|
+
siginfo_t sig = {0};
|
609
|
+
|
610
|
+
sig.si_signo = NUM2UINT(hash_get_int( h, rb_str_new_cstr("signo") ));
|
611
|
+
sig.si_errno = NUM2UINT(hash_get_int( h, rb_str_new_cstr("errno") ));
|
612
|
+
sig.si_code = NUM2UINT(hash_get_int( h, rb_str_new_cstr("code") ));
|
613
|
+
sig.si_trapno = NUM2UINT(hash_get_int( h, rb_str_new_cstr("trapno") ));
|
614
|
+
sig.si_pid = num_to_pid(hash_get_int( h, rb_str_new_cstr("pid") ));
|
615
|
+
sig.si_uid = NUM2UIDT(hash_get_int( h, rb_str_new_cstr("uid") ));
|
616
|
+
sig.si_status = NUM2UINT(hash_get_int( h, rb_str_new_cstr("status") ));
|
617
|
+
sig.si_utime = NUM2UINT(hash_get_int( h, rb_str_new_cstr("utime") ));
|
618
|
+
sig.si_stime = NUM2UINT(hash_get_int( h, rb_str_new_cstr("stime") ));
|
619
|
+
sig.si_value = NUM2UINT(hash_get_int( h, rb_str_new_cstr("value") ));
|
620
|
+
sig.si_int = NUM2UINT(hash_get_int( h, rb_str_new_cstr("int") ));
|
621
|
+
sig.si_ptr = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("ptr") ));
|
622
|
+
sig.si_overrun = NUM2UINT(hash_get_int(h, rb_str_new_cstr("overrun")));
|
623
|
+
sig.si_timerid = NUM2UINT(hash_get_int(h, rb_str_new_cstr("timerid")));
|
624
|
+
sig.si_addr = NUM2ULONG(hash_get_int( h, rb_str_new_cstr("addr") ));
|
625
|
+
sig.si_band = NUM2UINT(hash_get_int( h, rb_str_new_cstr("band") ));
|
626
|
+
sig.si_fd = NUM2UINT(hash_get_int( h, rb_str_new_cstr("fd") ));
|
627
|
+
|
628
|
+
int_ptrace_raw( PT_SETSIGINFO, pid, NULL, &sig);
|
629
|
+
# elif defined(__APPLE__)
|
630
|
+
# endif
|
631
|
+
#endif
|
632
|
+
return rv;
|
633
|
+
}
|
634
|
+
|
635
|
+
static VALUE ptrace_eventmsg( VALUE cls, VALUE pid ) {
|
636
|
+
VALUE rv = Qnil;
|
637
|
+
#ifdef PT_GETEVENTMSG
|
638
|
+
unsigned long long msg;
|
639
|
+
|
640
|
+
int_ptrace_raw( PT_GETEVENTMSG, pid, NULL, &msg);
|
641
|
+
rv = ULL2NUM(msg);
|
642
|
+
#endif
|
643
|
+
return rv;
|
644
|
+
}
|
645
|
+
|
646
|
+
/* ---------------------------------------------------------------------- */
|
647
|
+
/* Debugger Class */
|
648
|
+
|
649
|
+
static void init_debugger_class( VALUE modPtrace ) {
|
650
|
+
clsDebug = rb_define_class_under(modPtrace, DEBUGGER_CLASS_NAME,
|
651
|
+
rb_cObject);
|
652
|
+
|
653
|
+
rb_define_singleton_method(clsDebug, "commands", build_cmd_hash, 0);
|
654
|
+
|
655
|
+
rb_define_singleton_method(clsDebug, "send_cmd", ptrace_send, 3);
|
656
|
+
rb_define_singleton_method(clsDebug, "send_data", ptrace_send_data, 4);
|
657
|
+
rb_define_singleton_method(clsDebug, "peek", ptrace_peek, 3);
|
658
|
+
rb_define_singleton_method(clsDebug, "poke", ptrace_poke, 4);
|
659
|
+
rb_define_singleton_method(clsDebug, "regs", ptrace_get_regs, 1);
|
660
|
+
rb_define_singleton_method(clsDebug, "regs=", ptrace_set_regs, 2);
|
661
|
+
rb_define_singleton_method(clsDebug, "fpregs", ptrace_get_fpregs, 1);
|
662
|
+
rb_define_singleton_method(clsDebug, "fpregs=", ptrace_set_fpregs, 2);
|
663
|
+
rb_define_singleton_method(clsDebug, "fpxregs", ptrace_get_fpxregs, 1);
|
664
|
+
rb_define_singleton_method(clsDebug, "fpxregs=", ptrace_set_fpxregs, 2);
|
665
|
+
rb_define_singleton_method(clsDebug, "signal", ptrace_get_siginfo, 1);
|
666
|
+
rb_define_singleton_method(clsDebug, "signal=", ptrace_set_siginfo, 2);
|
667
|
+
rb_define_singleton_method(clsDebug, "event_msg", ptrace_eventmsg, 1);
|
668
|
+
}
|
669
|
+
|
670
|
+
/* ---------------------------------------------------------------------- */
|
671
|
+
/* USER */
|
672
|
+
|
673
|
+
/* ---------------------------------------------------------------------- */
|
674
|
+
/* Ptrace Module */
|
675
|
+
|
676
|
+
void Init_Ptrace_ext() {
|
677
|
+
modPtrace = rb_define_module(PTRACE_MODULE_NAME);
|
678
|
+
clsError = rb_define_class_under(rb_eRuntimeError,
|
679
|
+
PTRACE_ERROR_CLASS_NAME,
|
680
|
+
rb_cObject);
|
681
|
+
|
682
|
+
init_debugger_class(modPtrace);
|
683
|
+
}
|