Ptrace 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|