tduehr-ragweed 0.1.5

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.
Files changed (62) hide show
  1. data/History.txt +15 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +30 -0
  5. data/examples/hittracertux.rb +48 -0
  6. data/examples/hittracerx.rb +63 -0
  7. data/examples/hook_notepad.rb +9 -0
  8. data/examples/snicker.rb +183 -0
  9. data/examples/tux-example.rb +23 -0
  10. data/lib/ragweed/arena.rb +55 -0
  11. data/lib/ragweed/blocks.rb +128 -0
  12. data/lib/ragweed/debugger32.rb +338 -0
  13. data/lib/ragweed/debuggerosx.rb +419 -0
  14. data/lib/ragweed/debuggertux.rb +347 -0
  15. data/lib/ragweed/detour.rb +223 -0
  16. data/lib/ragweed/ptr.rb +48 -0
  17. data/lib/ragweed/rasm/isa.rb +1046 -0
  18. data/lib/ragweed/rasm/util.rb +26 -0
  19. data/lib/ragweed/rasm.rb +53 -0
  20. data/lib/ragweed/sbuf.rb +197 -0
  21. data/lib/ragweed/trampoline.rb +103 -0
  22. data/lib/ragweed/utils.rb +87 -0
  23. data/lib/ragweed/wrap32/debugging.rb +163 -0
  24. data/lib/ragweed/wrap32/device.rb +49 -0
  25. data/lib/ragweed/wrap32/event.rb +50 -0
  26. data/lib/ragweed/wrap32/hooks.rb +23 -0
  27. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  28. data/lib/ragweed/wrap32/process.rb +506 -0
  29. data/lib/ragweed/wrap32/process_token.rb +59 -0
  30. data/lib/ragweed/wrap32/thread_context.rb +208 -0
  31. data/lib/ragweed/wrap32/winx.rb +16 -0
  32. data/lib/ragweed/wrap32/wrap32.rb +526 -0
  33. data/lib/ragweed/wrap32.rb +53 -0
  34. data/lib/ragweed/wraposx/constants.rb +101 -0
  35. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  36. data/lib/ragweed/wraposx/region_info.rb +244 -0
  37. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  38. data/lib/ragweed/wraposx/thread_info.rb +213 -0
  39. data/lib/ragweed/wraposx/wraposx.rb +376 -0
  40. data/lib/ragweed/wraposx.rb +53 -0
  41. data/lib/ragweed/wraptux/constants.rb +68 -0
  42. data/lib/ragweed/wraptux/threads.rb +3 -0
  43. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  44. data/lib/ragweed/wraptux.rb +53 -0
  45. data/lib/ragweed.rb +84 -0
  46. data/spec/ragweed_spec.rb +7 -0
  47. data/spec/spec_helper.rb +16 -0
  48. data/tasks/ann.rake +80 -0
  49. data/tasks/bones.rake +20 -0
  50. data/tasks/gem.rake +201 -0
  51. data/tasks/git.rake +40 -0
  52. data/tasks/notes.rake +27 -0
  53. data/tasks/post_load.rake +34 -0
  54. data/tasks/rdoc.rake +51 -0
  55. data/tasks/rubyforge.rake +55 -0
  56. data/tasks/setup.rb +292 -0
  57. data/tasks/spec.rake +54 -0
  58. data/tasks/svn.rake +47 -0
  59. data/tasks/test.rake +40 -0
  60. data/tasks/zentest.rake +36 -0
  61. data/test/test_ragweed.rb +0 -0
  62. metadata +127 -0
@@ -0,0 +1,213 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx::ThreadInfo
3
+
4
+ # info interfaces
5
+ BASIC_INFO = 3 #basic information
6
+
7
+ # following are obsolete interfaces
8
+ # according to the source @ fxr they still work except FIFO
9
+ SCHED_TIMESHARE_INFO = 10
10
+ SCHED_RR_INFO = 11
11
+ # SCHED_FIFO_INFO = 12
12
+
13
+ FLAVORS = {
14
+ # define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
15
+ BASIC_INFO => {:size => 30, :count => 10},
16
+ # define POLICY_TIMESHARE_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_timeshare_info)/sizeof(integer_t)))
17
+ SCHED_TIMESHARE_INFO => {:size => 20, :count => 5},
18
+ # define POLICY_RR_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_rr_info)/sizeof(integer_t)))
19
+ SCHED_RR_INFO => {:size => 20,:count => 5},
20
+ # define POLICY_FIFO_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_fifo_info)/sizeof(integer_t)))
21
+ # SCHED_FIFO_INFO => {:size => 16,:count => 4} # immediately returns KERNEL_INVALID_POLICY on osx
22
+ }
23
+
24
+ module State
25
+ #Thread run states
26
+ RUNNING = 1 #/* thread is running normally */
27
+ STOPPED = 2 #/* thread is stopped */
28
+ WAITING = 3 #/* thread is waiting normally */
29
+ UNINTERRUPTIBLE = 4 #/* thread is in an uninterruptible wait */
30
+ HALTED = 5 #/* thread is halted at a clean point */
31
+ end
32
+
33
+ module ThreadInfoMixins
34
+ def initialize(str=nil)
35
+ refresh(str) if (str && !str.empty?)
36
+ end
37
+
38
+ # (re)loads the data from str
39
+ def refresh(str)
40
+ fields = self.class.const_get :FIELDS
41
+ pp self.class
42
+ if str and not str.empty?
43
+ str.unpack(fields.map {|x| x[1]}.join("")).each_with_index do |val, i|
44
+ raise "i is nil" if i.nil?
45
+ instance_variable_set "@#{ fields[i][0] }".intern, val
46
+ end
47
+ end
48
+ end
49
+
50
+ def to_s
51
+ fields = self.class.const_get :FIELDS
52
+ fields.map {|f| send(f[0])}.pack(fields.map {|x| x[1]}.join(""))
53
+ end
54
+
55
+ def inspect
56
+ body = lambda do
57
+ self.class.const_get(:FIELDS).map do |f|
58
+ "#{f[0]}=#{send(f[0]).to_s}"
59
+ end.join(", ")
60
+ end
61
+ "#<#{self.class} #{body.call}>"
62
+ end
63
+
64
+ def self.get(t)
65
+ self.new(Ragweed::Wraposx::thread_info_raw(t, self.class.const_get(:FLAVOR)))
66
+ end
67
+
68
+ def get(t)
69
+ refresh(Ragweed::Wraposx::vm_region_raw(t, self.class.const_get(:FLAVOR)))
70
+ end
71
+ end
72
+
73
+ # struct thread_basic_info
74
+ # {
75
+ # time_value_t user_time;
76
+ # time_value_t system_time;
77
+ # integer_t cpu_usage;
78
+ # policy_t policy;
79
+ # integer_t run_state;
80
+ # integer_t flags;
81
+ # integer_t suspend_count;
82
+ # integer_t sleep_time;
83
+ # };
84
+ class Basic
85
+ include Ragweed::Wraposx::ThreadInfo::ThreadInfoMixins
86
+ module Flags
87
+ #Thread flags (flags field).
88
+ SWAPPED = 0x1 #/* thread is swapped out */
89
+ IDLE = 0x2 #/* thread is an idle thread */
90
+ end
91
+
92
+ attr_accessor :user_time
93
+ attr_accessor :system_time
94
+ alias_method :__refresh :refresh
95
+ (FIELDS = [ [:user_time_s, "I"],
96
+ [:user_time_us, "I"],
97
+ [:system_time_s, "I"],
98
+ [:system_time_us, "I"],
99
+ [:cpu_usage, "I"],
100
+ [:policy, "I"],
101
+ [:run_state, "I"],
102
+ [:flags, "I"],
103
+ [:suspend_count, "I"],
104
+ [:sleep_time, "I"]]).each {|x| attr_accessor x[0]}
105
+
106
+ FLAVOR = Ragweed::Wraposx::ThreadInfo::BASIC_INFO
107
+ #(re)loads the data from str
108
+ def refresh(str)
109
+ __refresh str
110
+ @user_time = @user_time_s + (@user_time_us/1000000.0)
111
+ @system_time = @system_time_s + (@system_time_us/1000000.0)
112
+ end
113
+
114
+ def dump(&block)
115
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
116
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
117
+
118
+ string =<<EOM
119
+ -----------------------------------------------------------------------
120
+ INFO:
121
+ user_time: #{self.user_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.user_time)}
122
+ system_time: #{self.system_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.system_time)}
123
+ cpu_usage: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cpu_usage)}
124
+ policy: #{self.policy.to_s.rjust(8, "0")} #{maybe_hex.call(self.policy)}
125
+ run_state: #{self.run_state.to_s.rjust(8, "0")} #{maybe_hex.call(self.run_state)}
126
+ suspend_count: #{self.suspend_count.to_s.rjust(8, "0")} #{maybe_hex.call(self.suspend_count)}
127
+ sleep_time: #{self.sleep_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.sleep_time)}
128
+ flags: #{self.flags.to_s(2).rjust(32, "0")} #{Flags.flag_dump(self.flags)}
129
+ EOM
130
+ end
131
+ end
132
+
133
+ # struct policy_timeshare_info
134
+ # {
135
+ # int max_priority;
136
+ # int base_priority;
137
+ # int cur_priority;
138
+ # boolean_t depressed;
139
+ # int depress_priority;
140
+ # };
141
+ class SchedTimeshare
142
+ include Ragweed::Wraposx::ThreadInfo::ThreadInfoMixins
143
+ (FIELDS = [ [:max_priority, "I"],
144
+ [:base_priority, "I"],
145
+ [:cur_priority, "I"],
146
+ [:depressed, "I"],
147
+ [:depress_priority, "I"]]).each {|x| attr_accessor x[0]}
148
+
149
+ def dump(&block)
150
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
151
+
152
+ string =<<EOM
153
+ -----------------------------------------------------------------------
154
+ Timeshare Info:
155
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
156
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
157
+ cur_priority: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cur_priority)}
158
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
159
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
160
+ EOM
161
+ end
162
+ end
163
+
164
+ # struct policy_rr_info
165
+ # {
166
+ # int max_priority;
167
+ # int base_priority;
168
+ # int quantum;
169
+ # boolean_t depressed;
170
+ # int depress_priority;
171
+ # };
172
+ class SchedRr
173
+ include Ragweed::Wraposx::ThreadInfo::ThreadInfoMixins
174
+ (FIELDS = [ [:max_priority, "I"],
175
+ [:base_priority, "I"],
176
+ [:quantum, "I"],
177
+ [:depressed, "I"],
178
+ [:depress_priority, "I"]]).each {|x| attr_accessor x[0]}
179
+
180
+ def dump(&block)
181
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
182
+
183
+ string =<<EOM
184
+ -----------------------------------------------------------------------
185
+ Round Robin Info:
186
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
187
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
188
+ quantum: #{self.quantum.to_s.rjust(8, "0")} #{maybe_hex.call(self.quantum)}
189
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
190
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
191
+ EOM
192
+ end
193
+ end
194
+ end
195
+
196
+ module Ragweed::Wraposx
197
+ class << self
198
+
199
+ # Returns the packed string representation of the thread_info_t struct for later parsing.
200
+ # kern_return_t thread_info
201
+ # (thread_act_t target_thread,
202
+ # thread_flavor_t flavor,
203
+ # thread_info_t thread_info,
204
+ # mach_msg_type_number_t thread_info_count);
205
+ def thread_info_raw(thread, flavor)
206
+ info = ("\x00"*1024).to_ptr
207
+ count = ([Ragweed::Wraposx::ThreadInfo::FLAVORS[flavor][:count]].pack("I_")).to_ptr
208
+ r = CALLS["libc!thread_info:IIPP=I"].call(thread,flavor,info,Ragweed::Wraposx::ThreadInfo::FLAVORS[flavor][:count]).first
209
+ raise KernelCallError.new(r) if r != 0
210
+ return info.to_s(Ragweed::Wraposx::ThreadInfo::FLAVORS[flavor][:size])
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,376 @@
1
+ require 'dl'
2
+
3
+ module Ragweed; end
4
+ module Ragweed::Wraposx
5
+
6
+ # These hashes are the magic glue of the ragweed system calls.
7
+ # This one holds the library references from Ruby/DL.
8
+ LIBS = Hash.new do |h, str|
9
+ if not str =~ /^[\.\/].*/
10
+ str = "/usr/lib/" + str
11
+ end
12
+ if not str =~ /.*\.dylib$/
13
+ str = str + ".dylib"
14
+ end
15
+ h[str] = DL.dlopen(str)
16
+ end
17
+
18
+ # This hash holds the function references from Ruby/DL.
19
+ # It also auto populates LIBS.
20
+ # CALLS["<library>!<function>:<argument types>=<return type>"]
21
+ # Hash.new is a beautiful thing.
22
+ CALLS = Hash.new do |h, str|
23
+ lib = proc = args = ret = nil
24
+ lib, rest = str.split "!"
25
+ proc, rest = rest.split ":"
26
+ args, ret = rest.split("=") if rest
27
+ ret ||= "0"
28
+ raise "need proc" if not proc
29
+ h[str] = LIBS[lib][proc, ret + args]
30
+ end
31
+
32
+ NULL = DL::PtrData.new(0)
33
+
34
+ SIZEOFINT = DL.sizeof('I')
35
+ SIZEOFLONG = DL.sizeof('L')
36
+
37
+ class << self
38
+
39
+ # time_t
40
+ # time(time_t *tloc);
41
+ #
42
+ # see also time(3)
43
+ def time
44
+ CALLS["libc!time:=I"].call.first
45
+ end
46
+
47
+ # pid_t
48
+ # getpid(void);
49
+ #
50
+ # see also getpid(2)
51
+ def getpid
52
+ CALLS["libc!getpid:=I"].call.first
53
+ end
54
+
55
+ # Apple's ptrace is fairly gimped. The memory read and write functionality has been
56
+ # removed. We will be using mach kernel calls for that. see vm_read and vm_write.
57
+ # for details on ptrace and the process for the Wraposx/debuggerosx port see:
58
+ # http://www.matasano.com/log/1100/what-ive-been-doing-on-my-summer-vacation-or-it-has-to-work-otherwise-gdb-wouldnt/
59
+ #
60
+ #int
61
+ #ptrace(int request, pid_t pid, caddr_t addr, int data);
62
+ #
63
+ # see also ptrace(2)
64
+ def ptrace(request, pid, addr, data)
65
+ DL.last_error = 0
66
+ r = CALLS["libc!ptrace:IIII=I"].call(request, pid, addr, data).first
67
+ raise SystemCallError.new("ptrace", DL.last_error) if r == -1 and DL.last_error != 0
68
+ return r
69
+ end
70
+
71
+ # Oringially coded for use in debuggerosx but I've switched to waitpid for
72
+ # usability and debugging purposes.
73
+ #
74
+ # Returns status of child when child recieves a signal.
75
+ #
76
+ # pid_t
77
+ # wait(int *stat_loc);
78
+ #
79
+ # see also wait(2)
80
+ def wait
81
+ status = ("\x00"*SIZEOFINT).to_ptr
82
+ r = CALLS["libc!wait:=I"].call(status).first
83
+ raise SystemCallError.new("wait", DL.last_error) if r== -1
84
+ return status.to_s(SIZEOFINT).unpack('i_').first
85
+ end
86
+
87
+ # The wait used in debuggerosx.
88
+ # opt is an OR of the options to be used.
89
+ #
90
+ # Returns an array. The first element is the pid of the child process
91
+ # as returned by the waitpid system call. The second, the status as
92
+ # an integer of that pid.
93
+ #
94
+ # pid_t
95
+ # waitpid(pid_t pid, int *stat_loc, int options);
96
+ #
97
+ # see also wait(2)
98
+ def waitpid(pid, opt=1)
99
+ pstatus = ("\x00"*SIZEOFINT).to_ptr
100
+ r = CALLS["libc!waitpid:IPI=I"].call(pid, pstatus, opt).first
101
+ raise SystemCallError.new("waitpid", DL.last_error) if r== -1
102
+
103
+ # maybe I should return a Hash?
104
+ return [r, pstatus.to_s(SIZEOFINT).unpack('i_').first]
105
+ end
106
+
107
+ # From docs at http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html
108
+ # Returns send rights to the task's kernel port.
109
+ #
110
+ # mach_port_t
111
+ # mach_task_self(void)
112
+ #
113
+ # There is no man page for this call.
114
+ def mach_task_self
115
+ CALLS["libc!mach_task_self:=I"].call().first
116
+ end
117
+
118
+ # Requires sudo to use as of 10.5 or 10.4.11(ish)
119
+ # Returns the task id for a process.
120
+ #
121
+ # kern_return_t task_for_pid(
122
+ # mach_port_name_t target_tport,
123
+ # int pid,
124
+ # mach_port_name_t *t);
125
+ #
126
+ # There is no man page for this call.
127
+ def task_for_pid(pid, target=nil)
128
+ target ||= mach_task_self
129
+ port = ("\x00"*SIZEOFINT).to_ptr
130
+ r = CALLS["libc!task_for_pid:IIP=I"].call(target, pid, port).first
131
+ raise KernelCallError.new(:task_for_pid, r) if r != 0
132
+ return port.to_s(SIZEOFINT).unpack('i_').first
133
+ end
134
+
135
+ # Returns an Array of thread IDs for the given task
136
+ #
137
+ # kern_return_t task_threads
138
+ # (task_t task,
139
+ # thread_act_port_array_t thread_list,
140
+ # mach_msg_type_number_t* thread_count);
141
+ #
142
+ #There is no man page for this funtion.
143
+ def task_threads(port)
144
+ threads = ("\x00"*SIZEOFINT).to_ptr
145
+ #threads = 0
146
+ count = ("\x00"*SIZEOFINT).to_ptr
147
+ r = CALLS["libc!task_threads:IPP=I"].call(port, threads, count).first
148
+ t = DL::PtrData.new(threads.to_s(SIZEOFINT).unpack('i_').first)
149
+ raise KernelCallError.new(:task_threads, r) if r != 0
150
+ return t.to_a("I", count.to_s(SIZEOFINT).unpack('I_').first)
151
+ end
152
+
153
+ # Sends a signal to a process
154
+ #
155
+ # int
156
+ # kill(pid_t pid, int sig);
157
+ #
158
+ # See kill(2)
159
+ def kill(pid, sig)
160
+ DL.last_error = 0
161
+ r = CALLS["libc!kill:II=I"].call(pid,sig).first
162
+ raise SystemCallError.new("kill",DL.last_error) if r != 0
163
+ end
164
+
165
+ # function to marshal 32bit integers into DL::PtrData objects
166
+ # necessary due to Ruby/DL not properly dealing with 31 and 32 bit integers
167
+ def dl_bignum_to_ulong(x)
168
+ if x.class == Fixnum
169
+ return DL::PtrData.new(x)
170
+ else
171
+ # shut up
172
+ c = x / 4
173
+ e = x - (c * 4)
174
+ v = DL::PtrData.new 0
175
+ v += c
176
+ v += c
177
+ v += c
178
+ v += c
179
+ v += e
180
+ return v
181
+ end
182
+ end
183
+
184
+ # Reads sz bytes from task's address space starting at addr.
185
+ #
186
+ # kern_return_t vm_read_overwrite
187
+ # (vm_task_t target_task,
188
+ # vm_address_t address,
189
+ # vm_size_t size,
190
+ # vm_address_t *data_out,
191
+ # mach_msg_type_number_t *data_size);
192
+ #
193
+ # There is no man page for this function.
194
+ def vm_read(task, addr, sz=256)
195
+ addr = dl_bignum_to_ulong(addr)
196
+ buf = ("\x00" * sz).to_ptr
197
+ len = (sz.to_l32).to_ptr
198
+ r = CALLS["libc!vm_read_overwrite:IPIPP=I"].call(task, addr, sz, buf, len).first
199
+ raise KernelCallError.new(:vm_read, r) if r != 0
200
+ return buf.to_str(len.to_str(4).to_l32)
201
+ end
202
+
203
+ # Writes val to task's memory space at address addr.
204
+ # It is necessary for val.size to report the size of val in bytes
205
+ #
206
+ # kern_return_t vm_write
207
+ # (vm_task_t target_task,
208
+ # vm_address_t address,
209
+ # pointer_t data,
210
+ # mach_msg_type_number_t data_count);
211
+ #
212
+ # There is no man page for this function.
213
+ def vm_write(task, addr, val)
214
+ addr = dl_bignum_to_ulong(addr)
215
+ val = val.to_ptr
216
+ r = CALLS["libc!vm_write:IPPI=I"].call(task, addr, val, val.size).first
217
+ raise KernelCallError.new(:vm_write, r) if r != 0
218
+ return nil
219
+ end
220
+
221
+ # Changes the protection state beginning at addr for size bytes to the mask prot.
222
+ # If setmax is true this will set the maximum permissions, otherwise it will set FIXME
223
+ #
224
+ # kern_return_t vm_protect
225
+ # (vm_task_t target_task,
226
+ # vm_address_t address,
227
+ # vm_size_t size,
228
+ # boolean_t set_maximum,
229
+ # vm_prot_t new_protection);
230
+ #
231
+ # There is no man page for this function.
232
+ def vm_protect(task, addr, size, setmax, prot)
233
+ addr = dl_bignum_to_ulong(addr)
234
+ setmax = setmax ? 1 : 0
235
+ r = CALLS["libc!vm_protect:IPIII=I"].call(task,addr,size,setmax,prot).first
236
+ raise KernelCallError.new(:vm_protect, r) if r != 0
237
+ return nil
238
+ end
239
+
240
+ # Resumes a suspended thread by id.
241
+ #
242
+ # kern_return_t thread_resume
243
+ # (thread_act_t target_thread);
244
+ #
245
+ # There is no man page for this function.
246
+ def thread_resume(thread)
247
+ r = CALLS["libc!thread_resume:I=I"].call(thread).first
248
+ raise KernelCallError.new(:thread_resume, r) if r != 0
249
+ end
250
+
251
+ # Suspends a thread by id.
252
+ #
253
+ # kern_return_t thread_suspend
254
+ # (thread_act_t target_thread);
255
+ #
256
+ # There is no man page for this function.
257
+ def thread_suspend(thread)
258
+ r = CALLS["libc!thread_suspend:I=I"].call(thread).first
259
+ raise KernelCallError.new(:thread_suspend, r) if r != 0
260
+ end
261
+
262
+ # Suspends a task by id.
263
+ #
264
+ # kern_return_t task_suspend
265
+ # (task_t task);
266
+ #
267
+ # There is no man page for this function.
268
+ def task_suspend(task)
269
+ r = CALLS["libc!task_suspend:I=I"].call(task).first
270
+ raise KernelCallError.new(:task_suspend, r) if r != 0
271
+ end
272
+
273
+ # Resumes a suspended task by id.
274
+ #
275
+ # kern_return_t task_resume
276
+ # (task_t task);
277
+ #
278
+ # There is no man page for this function.
279
+ def task_resume(task)
280
+ r = CALLS["libc!task_resume:I=I"].call(task).first
281
+ raise KernelCallError.new(:task_resume, r) if r != 0
282
+ end
283
+
284
+ # Used to query kernel state.
285
+ # Returns output buffer on successful call or required buffer size on ENOMEM.
286
+ #
287
+ # mib: and array of integers decribing the MIB
288
+ # newb: the buffer to replace the old information (only used on some commands so it defaults to empty)
289
+ # oldlenp: output buffer size
290
+ #
291
+ # int
292
+ # sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
293
+ #
294
+ # this function doesn't really match the Ruby Way(tm)
295
+ #
296
+ # see sysctl(8)
297
+ def sysctl(mib,oldlen=0,newb="")
298
+ DL.last_error = 0
299
+ mibp = mib.pack("I_"*mib.size).to_ptr
300
+ oldlenp = [oldlen].pack("I_").to_ptr
301
+ namelen = mib.size
302
+ oldp = (oldlen > 0 ? "\x00"*oldlen : NULL)
303
+ newp = (newb.empty? ? NULL : newb.to_ptr)
304
+ newlen = newb.size
305
+ r = CALLS["libc!sysctl:PIPPPI=I"].call(mibp, namelen, oldp, oldlenp, newp, newlen).first
306
+ return oldlenp.to_str(SIZEOFINT).unpack("I_").first if (r == -1 and DL.last_error == Errno::ENOMEM::Errno)
307
+ raise SystemCallError.new("sysctl", DL.last_error) if r != 0
308
+ return oldp.to_str(oldlenp.to_str(SIZEOFINT).unpack("I_").first)
309
+ end
310
+
311
+ # Used to query kernel state.
312
+ # Returns output buffer on successful call and required buffer size as an Array.
313
+ #
314
+ # mib: and array of integers decribing the MIB
315
+ # newb: the buffer to replace the old information (only used on some commands so it defaults to empty)
316
+ # oldlenp: output buffer size
317
+ #
318
+ # int
319
+ # sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
320
+ #
321
+ # this function doesn't really match the Ruby Way(tm)
322
+ #
323
+ # see sysctl(8)
324
+ def sysctl_raw(mib,oldlen=0,newb="")
325
+ DL.last_error = 0
326
+ mibp = mib.pack('I_'*mib.size).to_ptr
327
+ oldlenp = [oldlen].pack("I_").to_ptr
328
+ namelen = mib.size
329
+ oldp = (oldlen > 0 ? ("\x00"*oldlen).to_ptr : NULL)
330
+ newp = (newb.empty? ? NULL : newb.to_ptr)
331
+ newlen = newb.size
332
+ r = CALLS["libc!sysctl:PIPPPI=I"].call(mibp, namelen, oldp, oldlenp, newp, newlen).first
333
+ ret = (DL.last_error == Errno::ENOMEM::Errno ? NULL : oldp)
334
+ raise SystemCallError.new("sysctl", DL.last_error) if (r != 0 and DL.last_error != Errno::ENOMEM::Errno)
335
+ return [ret,oldlenp.to_str(SIZEOFINT).unpack("I_").first]
336
+ end
337
+
338
+ # Changes execution to file in path with *args as though called from command line.
339
+ #
340
+ # int
341
+ # execv(const char *path, char *const argv[]);
342
+ def execv(path,*args)
343
+ DL.last_error = 0
344
+ argv = ""
345
+ args.flatten.each { |arg| argv = "#{ argv }#{arg.to_ptr.ref.to_s(SIZEOFINT)}" }
346
+ argv += ("\x00"*SIZEOFINT)
347
+ r = CALLS["libc!execv:SP"].call(path,argv.to_ptr).first
348
+ raise SystemCallError.new("execv", DL.last_error) if r == -1
349
+ return r
350
+ end
351
+ end
352
+ end
353
+
354
+ # if __FILE__ == $0
355
+ # include Ragweed
356
+ # require 'pp'
357
+ # require 'constants'
358
+ # addr = data = 0
359
+ # pid = 1319
360
+ # int = "\x00" * 4
361
+ # port = 0
362
+ # Wraposx::ptrace(Wraposx::Ptrace::ATTACH,pid,0,0)
363
+ # # status = Wraposx::waitpid(pid,0)
364
+ # # Wraposx::ptrace(Wraposx::Ptrace::CONTINUE,pid,1,0)
365
+ # mts = Wraposx::mach_task_self
366
+ # port = Wraposx::task_for_pid(mts,pid)
367
+ # port2 = Wraposx::task_for_pid(mts,pid)
368
+ # threads = Wraposx::task_threads(port)
369
+ # state = Wraposx::thread_get_state(threads.first)
370
+ # pp port
371
+ # pp port2
372
+ # pp threads
373
+ # pp state
374
+ # # Wraposx::thread_set_state(threads.first,state)
375
+ # Wraposx::ptrace(Wraposx::Ptrace::DETACH,pid,0,0)
376
+ # end
@@ -0,0 +1,53 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/wraposx/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Wraposx
6
+
7
+ # :stopdoc:
8
+ VERSION = '0.1.5'
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility method used to require all files ending in .rb that lie in the
36
+ # directory below this file that has the same name as the filename passed
37
+ # in. Optionally, a specific _directory_ name can be passed in such that
38
+ # the _filename_ does not have to be equivalent to the directory.
39
+ #
40
+ def self.require_all_libs_relative_to( fname, dir = nil )
41
+ dir ||= ::File.basename(fname, '.*')
42
+ search_me = ::File.expand_path(
43
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
+
45
+ Dir.glob(search_me).sort.each {|rb| require rb}
46
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
47
+
48
+ end
49
+ end # module Ragweed::Wraposx
50
+
51
+ Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
52
+
53
+ # EOF