ragweed 0.2.0-java

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 (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -0
@@ -0,0 +1,160 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx::ThreadInfo
3
+ # info interfaces
4
+ BASIC_INFO = 3 #basic information
5
+
6
+ # following are obsolete interfaces
7
+ # according to the source @ fxr they still work except FIFO
8
+ SCHED_TIMESHARE_INFO = 10
9
+ SCHED_RR_INFO = 11
10
+ # SCHED_FIFO_INFO = 12
11
+
12
+ module State
13
+ #Thread run states
14
+ RUNNING = 1 #/* thread is running normally */
15
+ STOPPED = 2 #/* thread is stopped */
16
+ WAITING = 3 #/* thread is waiting normally */
17
+ UNINTERRUPTIBLE = 4 #/* thread is in an uninterruptible wait */
18
+ HALTED = 5 #/* thread is halted at a clean point */
19
+ end
20
+
21
+ # struct thread_basic_info
22
+ # {
23
+ # time_value_t user_time;
24
+ # time_value_t system_time;
25
+ # integer_t cpu_usage;
26
+ # policy_t policy;
27
+ # integer_t run_state;
28
+ # integer_t flags;
29
+ # integer_t suspend_count;
30
+ # integer_t sleep_time;
31
+ # };
32
+ class Basic < FFI::Struct
33
+ include Ragweed::FFIStructInclude
34
+ module Flags
35
+ #Thread flags (flags field).
36
+ SWAPPED = 0x1 #/* thread is swapped out */
37
+ IDLE = 0x2 #/* thread is an idle thread */
38
+ end
39
+
40
+ FLAVOR = Ragweed::Wraposx::ThreadInfo::BASIC_INFO
41
+ layout :user_time, Ragweed::Wraposx::TimeValue,
42
+ :system_time, Ragweed::Wraposx::TimeValue,
43
+ :cpu_usage, :int,
44
+ :policy, Ragweed::Wraposx::Libc.find_type(:policy_t),
45
+ :run_state, :int,
46
+ :flags, :int,
47
+ :suspend_count, :int,
48
+ :sleep_time, :int
49
+
50
+ def dump(&block)
51
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
52
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
53
+
54
+ string =<<EOM
55
+ -----------------------------------------------------------------------
56
+ INFO:
57
+ user_time: #{self.user_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.user_time)}
58
+ system_time: #{self.system_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.system_time)}
59
+ cpu_usage: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cpu_usage)}
60
+ policy: #{self.policy.to_s.rjust(8, "0")} #{maybe_hex.call(self.policy)}
61
+ run_state: #{self.run_state.to_s.rjust(8, "0")} #{maybe_hex.call(self.run_state)}
62
+ suspend_count: #{self.suspend_count.to_s.rjust(8, "0")} #{maybe_hex.call(self.suspend_count)}
63
+ sleep_time: #{self.sleep_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.sleep_time)}
64
+ flags: #{self.flags.to_s(2).rjust(32, "0")} #{Flags.flag_dump(self.flags)}
65
+ EOM
66
+ end
67
+ end
68
+
69
+ # struct policy_timeshare_info
70
+ # {
71
+ # int max_priority;
72
+ # int base_priority;
73
+ # int cur_priority;
74
+ # boolean_t depressed;
75
+ # int depress_priority;
76
+ # };
77
+ class SchedTimeshare < FFI::Struct
78
+ include Ragweed::FFIStructInclude
79
+ layout :max_priority, :int,
80
+ :base_priority, :int,
81
+ :cur_priority, :int,
82
+ :depress_priority, :int
83
+
84
+ def dump(&block)
85
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
86
+
87
+ string =<<EOM
88
+ -----------------------------------------------------------------------
89
+ Timeshare Info:
90
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
91
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
92
+ cur_priority: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cur_priority)}
93
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
94
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
95
+ EOM
96
+ end
97
+ end
98
+
99
+ # struct policy_rr_info
100
+ # {
101
+ # int max_priority;
102
+ # int base_priority;
103
+ # int quantum;
104
+ # boolean_t depressed;
105
+ # int depress_priority;
106
+ # };
107
+ class SchedRr < FFI::Struct
108
+ include Ragweed::FFIStructInclude
109
+ layout :max_priority, :int,
110
+ :base_priority, :int,
111
+ :quantum, :int,
112
+ :depressed, Ragweed::Wraposx::Libc.find_type(:boolean_t),
113
+ :depress_priority, :int
114
+
115
+ def dump(&block)
116
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
117
+
118
+ string =<<EOM
119
+ -----------------------------------------------------------------------
120
+ Round Robin Info:
121
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
122
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
123
+ quantum: #{self.quantum.to_s.rjust(8, "0")} #{maybe_hex.call(self.quantum)}
124
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
125
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
126
+ EOM
127
+ end
128
+ end
129
+
130
+ FLAVORS = {
131
+ # define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
132
+ BASIC_INFO => {:size => 30, :count => 10, :class => Basic},
133
+ # define POLICY_TIMESHARE_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_timeshare_info)/sizeof(integer_t)))
134
+ SCHED_TIMESHARE_INFO => {:size => 20, :count => 5, :class => SchedTimeshare},
135
+ # define POLICY_RR_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_rr_info)/sizeof(integer_t)))
136
+ SCHED_RR_INFO => {:size => 20,:count => 5, :class => SchedRr},
137
+ # define POLICY_FIFO_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_fifo_info)/sizeof(integer_t)))
138
+ # SCHED_FIFO_INFO => {:size => 16,:count => 4} # immediately returns KERNEL_INVALID_POLICY on osx
139
+ }
140
+ end
141
+
142
+ module Ragweed::Wraposx
143
+ class << self
144
+
145
+ # Returns the packed string representation of the thread_info_t struct for later parsing.
146
+ #
147
+ # kern_return_t thread_info
148
+ # (thread_act_t target_thread,
149
+ # thread_flavor_t flavor,
150
+ # thread_info_t thread_info,
151
+ # mach_msg_type_number_t thread_info_count);
152
+ def thread_info(thread, flavor)
153
+ info = FFI::MemoryPointer.new(ThreadInfo::FLAVORS[flavor][:class], 1)
154
+ count = FFI::MemoryPointer.new(:int, 1).write_int(ThreadInfo::FLAVORS[flavor][:count])
155
+ r = Libc.thread_info(thread, flavor, info, count)
156
+ raise KernelCallError.new(r) if r != 0
157
+ ThreadInfo::FLAVORS[flavor][:class].new info
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,121 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx::ThreadState
3
+ #Thread run states
4
+ RUNNING = 1 #/* thread is running normally */
5
+ STOPPED = 2 #/* thread is stopped */
6
+ WAITING = 3 #/* thread is waiting normally */
7
+ UNINTERRUPTIBLE = 4 #/* thread is in an uninterruptible wait */
8
+ HALTED = 5 #/* thread is halted at a clean point */
9
+ end
10
+
11
+ module Ragweed::Wraposx::TFlags
12
+ #Thread flags (flags field).
13
+ SWAPPED = 0x1 #/* thread is swapped out */
14
+ IDLE = 0x2 #/* thread is an idle thread */
15
+ end
16
+
17
+ class Ragweed::Wraposx::ThreadInfo
18
+ include Ragweed
19
+ attr_accessor :user_time
20
+ attr_accessor :system_time
21
+ (FIELDS = [ [:user_time_s, "I"],
22
+ [:user_time_us, "I"],
23
+ [:system_time_s, "I"],
24
+ [:system_time_us, "I"],
25
+ [:cpu_usage, "I"],
26
+ [:policy, "I"],
27
+ [:run_state, "I"],
28
+ [:flags, "I"],
29
+ [:suspend_count, "I"],
30
+ [:sleep_time, "I"]]).each {|x| attr_accessor x[0]}
31
+
32
+ def initialize(str=nil)
33
+ refresh(str) if str
34
+ end
35
+
36
+ #(re)loads the data from str
37
+ def refresh(str)
38
+ if str and not str.empty?
39
+ str.unpack(FIELDS.map {|x| x[1]}.join("")).each_with_index do |val, i|
40
+ raise "i is nil" if i.nil?
41
+ instance_variable_set "@#{ FIELDS[i][0] }".intern, val
42
+ end
43
+ end
44
+ @user_time = @user_time_s + (@user_time_us/1000000.0)
45
+ @system_time = @system_time_s + (@system_time_us/1000000.0)
46
+ end
47
+
48
+ def to_s
49
+ FIELDS.map {|f| send(f[0])}.pack(FIELDS.map {|x| x[1]}.join(""))
50
+ end
51
+
52
+ def self.get(t)
53
+ self.new(Wraposx::thread_info_raw(t))
54
+ end
55
+
56
+ def get(t)
57
+ refresh(Wraposx::thread_info_raw(t))
58
+ end
59
+
60
+ def inspect
61
+ body = lambda do
62
+ FIELDS.map do |f|
63
+ "#{f[0]}=#{send(f[0]).to_s}"
64
+ end.join(", ")
65
+ end
66
+ "#<ThreadInfo #{body.call}>"
67
+ end
68
+
69
+ def dump(&block)
70
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
71
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
72
+
73
+ string =<<EOM
74
+ -----------------------------------------------------------------------
75
+ INFO:
76
+ user_time: #{self.user_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.user_time)}
77
+ system_time: #{self.system_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.system_time)}
78
+ cpu_usage: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cpu_usage)}
79
+ policy: #{self.policy.to_s.rjust(8, "0")} #{maybe_hex.call(self.policy)}
80
+ run_state: #{self.run_state.to_s.rjust(8, "0")} #{maybe_hex.call(self.run_state)}
81
+ suspend_count: #{self.suspend_count.to_s.rjust(8, "0")} #{maybe_hex.call(self.suspend_count)}
82
+ sleep_time: #{self.sleep_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.sleep_time)}
83
+ flags: #{self.flags.to_s(2).rjust(32, "0")} #{Wraposx::TFlags.flag_dump(self.flags)}
84
+ EOM
85
+ end
86
+ end
87
+
88
+ module Ragweed::Wraposx
89
+
90
+ # FIXME - constants should be under separate sub-modules
91
+ # XXX - implement more thread info flavors (if possible)
92
+ # XXX - move to class based implementation a la region_info
93
+ # info interfaces
94
+ THREAD_BASIC_INFO = 3 #basic information
95
+
96
+ # following are obsolete interfaces
97
+ THREAD_SCHED_TIMESHARE_INFO = 10
98
+ THREAD_SCHED_RR_INFO = 11
99
+ THREAD_SCHED_FIFO_INFO = 12
100
+
101
+ # define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
102
+ # the two time fields are each two ints
103
+ THREAD_BASIC_INFO_COUNT = 10
104
+
105
+ class << self
106
+
107
+ # Returns the packed string representation of the thread_info_t struct for later parsing.
108
+ # kern_return_t thread_info
109
+ # (thread_act_t target_thread,
110
+ # thread_flavor_t flavor,
111
+ # thread_info_t thread_info,
112
+ # mach_msg_type_number_t thread_info_count);
113
+ def thread_info_raw(thread)
114
+ info = ("\x00"*1024).to_ptr
115
+ count = ([THREAD_BASIC_INFO_COUNT].pack("I_")).to_ptr
116
+ r = CALLS["libc!thread_info:IIPP=I"].call(thread,THREAD_BASIC_INFO,info,count).first
117
+ raise KernelCallError.new(:thread_info, r) if r != 0
118
+ return info.to_s(SIZEOFINT*THREAD_BASIC_INFO_COUNT)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,356 @@
1
+ require 'ffi'
2
+
3
+ module Ragweed; end
4
+ module Ragweed::Wraposx
5
+
6
+ module Libc
7
+ extend FFI::Library
8
+ ffi_lib FFI::Library::LIBC
9
+ typedef :int, :kern_return_t
10
+
11
+ typedef :ulong_long, :memory_object_offset_t
12
+ typedef :uint, :vm_inherit_t
13
+ typedef :uint, :natural_t
14
+ typedef :natural_t, :mach_msg_type_number_t
15
+ typedef :natural_t, :mach_port_name_t
16
+ typedef :mach_port_name_t, :mach_port_t
17
+ typedef :mach_port_t, :vm_map_t
18
+ typedef :mach_port_t, :task_t
19
+ typedef :mach_port_t, :thread_act_t
20
+ typedef :int, :vm_region_flavor_t
21
+ typedef :int, :vm_prot_t
22
+ typedef :int, :vm_behavior_t
23
+ typedef :int, :policy_t
24
+ typedef :int, :boolean_t
25
+ typedef :int, :thread_state_flavor_t
26
+ case FFI::Platform::LONG_SIZE
27
+ when 64
28
+ # ifdef __LP64__
29
+ typedef :uintptr_t, :vm_size_t
30
+ typedef :uintptr_t, :vm_offset_t
31
+ when 32
32
+ # else /* __LP64__ */
33
+ typedef :natural_t, :vm_size_t
34
+ typedef :natural_t, :vm_offset_t
35
+ else
36
+ raise "Unsupported Platform"
37
+ end
38
+
39
+ typedef :vm_offset_t, :vm_address_t
40
+
41
+ attach_function :getpid, [], :pid_t
42
+ attach_function :ptrace, [:int, :pid_t, :ulong, :int], :int
43
+ attach_function :wait, [:pointer], :pid_t
44
+ attach_function :waitpid, [:pid_t, :pointer, :int], :pid_t
45
+ attach_function :mach_task_self, [], :mach_port_t
46
+ attach_function :task_for_pid, [:mach_port_name_t, :int, :pointer], :kern_return_t
47
+ attach_function :task_threads, [:task_t, :pointer, :pointer], :kern_return_t
48
+ attach_function :kill, [:pid_t, :int], :int
49
+ attach_function :vm_read_overwrite, [:vm_map_t, :vm_address_t, :vm_size_t, :vm_address_t, :pointer], :kern_return_t
50
+ attach_function :vm_write, [:vm_map_t, :vm_address_t, :vm_offset_t, :mach_msg_type_number_t], :kern_return_t
51
+ attach_function :vm_protect, [:vm_map_t, :vm_address_t, :vm_size_t, :boolean_t, :vm_prot_t], :kern_return_t
52
+ attach_function :vm_allocate, [:vm_map_t, :pointer, :vm_size_t, :int], :kern_return_t
53
+ attach_function :vm_deallocate, [:vm_map_t, :vm_address_t, :vm_size_t], :kern_return_t
54
+ attach_function :thread_resume, [:thread_act_t], :kern_return_t
55
+ attach_function :thread_suspend, [:thread_act_t], :kern_return_t
56
+ attach_function :task_suspend, [:int], :kern_return_t
57
+ attach_function :task_resume, [:int], :kern_return_t
58
+ attach_function :sysctl, [:pointer, :int, :pointer, :pointer, :pointer, :int], :int
59
+ attach_function :execv, [:string, :pointer], :int
60
+ end
61
+
62
+ class << self
63
+
64
+ # pid_t
65
+ # getpid(void);
66
+ #
67
+ # see also getpid(2)
68
+ def getpid
69
+ Libc.getpid
70
+ end
71
+
72
+ # Apple's ptrace is fairly gimped. The memory read and write functionality has been
73
+ # removed. We will be using mach kernel calls for that. see vm_read and vm_write.
74
+ # for details on ptrace and the process for the Wraposx/debuggerosx port see:
75
+ # http://www.matasano.com/log/1100/what-ive-been-doing-on-my-summer-vacation-or-it-has-to-work-otherwise-gdb-wouldnt/
76
+ #
77
+ #int
78
+ #ptrace(int request, pid_t pid, caddr_t addr, int data);
79
+ #
80
+ # see also ptrace(2)
81
+ def ptrace(request, pid, addr, data)
82
+ FFI.errno = 0
83
+ r = Libc.ptrace(request, pid, addr, data)
84
+ raise SystemCallError.new("ptrace", FFI.errno) if r == -1 and FFI.errno != 0
85
+ [r, data]
86
+ end
87
+
88
+ # ptrace(PT_TRACE_ME, ...)
89
+ def pt_trace_me pid
90
+ ptrace(Ragweed::Wraposx::Ptrace::TRACE_ME, pid, nil, nil).first
91
+ end
92
+
93
+ # ptrace(PT_DENY_ATTACH, ... )
94
+ def pt_deny_attach pid
95
+ ptrace(Ragweed::Wraposx::Ptrace::DENY_ATTACH, pid, nil, nil).first
96
+ end
97
+
98
+ # ptrace(PT_CONTINUE, pid, addr, signal)
99
+ def pt_continue pid, addr = 1, sig = 0
100
+ ptrace(Ragweed::Wraposx::Ptrace::CONTINUE, pid, addr, sig).first
101
+ end
102
+
103
+ # ptrace(PT_STEP, pid, addr, signal)
104
+ def pt_step pid, addr = 1, sig = 0
105
+ ptrace(Ragweed::Wraposx::Ptrace::STEP, pid, addr, sig).first
106
+ end
107
+
108
+ # ptrace(PT_KILL, ... )
109
+ def pt_kill pid
110
+ ptrace(Ragweed::Wraposx::Ptrace::KILL, pid, nil, nil).first
111
+ end
112
+
113
+ # ptrace(PT_ATTACH, ... )
114
+ def pt_attach pid
115
+ ptrace(Ragweed::Wraposx::Ptrace::ATTACH, pid, nil, nil).first
116
+ end
117
+
118
+ # ptrace(PT_DETACH, ... )
119
+ def pt_detach pid
120
+ ptrace(Ragweed::Wraposx::Ptrace::DETACH, pid, nil, nil).first
121
+ end
122
+
123
+ # Originally coded for use in debuggerosx but I've switched to waitpid for
124
+ # usability and debugging purposes.
125
+ #
126
+ # Returns status of child when child recieves a signal.
127
+ #
128
+ # pid_t
129
+ # wait(int *stat_loc);
130
+ #
131
+ # see also wait(2)
132
+ def wait
133
+ stat = FFI::MemoryPointer.new :int, 1
134
+ FFI.errno = 0
135
+ pid = Libc.wait stat
136
+ raise SystemCallError.new "wait", FFI.errno if pid == -1
137
+ [pid, stat.read_int]
138
+ end
139
+
140
+ # The wait used in debuggerosx.
141
+ # opt is an OR of the options to be used.
142
+ #
143
+ # Returns an array. The first element is the pid of the child process
144
+ # as returned by the waitpid system call. The second, the status as
145
+ # an integer of that pid.
146
+ #
147
+ # pid_t
148
+ # waitpid(pid_t pid, int *stat_loc, int options);
149
+ #
150
+ # see also wait(2)
151
+ def waitpid pid, opts = 0
152
+ stat = FFI::MemoryPointer.new :int, 1
153
+ FFI.errno = 0
154
+ r = Libc.waitpid(pid, stat, opts)
155
+ raise SystemCallError.new "waitpid", FFI.errno if r == -1
156
+ [r, stat.read_int]
157
+ end
158
+
159
+ # From docs at http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html
160
+ # Returns send rights to the task's kernel port.
161
+ #
162
+ # mach_port_t
163
+ # mach_task_self(void)
164
+ #
165
+ # There is no man page for this call.
166
+ def mach_task_self
167
+ Libc.mach_task_self
168
+ end
169
+
170
+ # Requires sudo to use as of 10.5 or 10.4.11(ish)
171
+ # Returns the task id for a process.
172
+ #
173
+ # kern_return_t task_for_pid(
174
+ # mach_port_name_t target_tport,
175
+ # int pid,
176
+ # mach_port_name_t *t);
177
+ #
178
+ # There is no man page for this call.
179
+ def task_for_pid(pid, target=nil)
180
+ target ||= mach_task_self
181
+ port = FFI::MemoryPointer.new :int, 1
182
+ r = Libc.task_for_pid(target, pid, port)
183
+ raise KernelCallError.new(:task_for_pid, r) if r != 0
184
+ port.read_int
185
+ end
186
+
187
+ # Returns an Array of thread IDs for the given task
188
+ #
189
+ # kern_return_t task_threads
190
+ # (task_t task,
191
+ # thread_act_port_array_t thread_list,
192
+ # mach_msg_type_number_t* thread_count);
193
+ #
194
+ #There is no man page for this funtion.
195
+ def task_threads(port)
196
+ threads = FFI::MemoryPointer.new :int, 1
197
+ count = FFI::MemoryPointer.new :int, 1
198
+ r = Libc.task_threads(port, threads, count)
199
+ raise KernelCallError.new(:task_threads, r) if r != 0
200
+ threads.read_array_of_int(count.read_int)
201
+ end
202
+
203
+ # Decrement the target tasks suspend count
204
+ # kern_return_t task_resume
205
+ # (task_t task);
206
+ def task_resume(task)
207
+ r = Libc.task_resume(task)
208
+ raise KernelCallError.new(r) if r != 0
209
+ r
210
+ end
211
+
212
+ # Increment the target tasks suspend count
213
+ # kern_return_t task_suspend
214
+ # (task_t task);
215
+ def task_suspend(task)
216
+ r = Libc.task_suspend(task)
217
+ raise KernelCallError.new(r) if r != 0
218
+ end
219
+
220
+ # Sends a signal to a process
221
+ #
222
+ # int
223
+ # kill(pid_t pid, int sig);
224
+ #
225
+ # See kill(2)
226
+ def kill(pid, sig)
227
+ FFI::errno = 0
228
+ r = Libc.kill(pid, sig)
229
+ raise SystemCallError.new "kill", FFI::errno if r != 0
230
+ end
231
+
232
+ # Reads sz bytes from task's address space starting at addr.
233
+ #
234
+ # kern_return_t vm_read_overwrite
235
+ # (vm_task_t target_task,
236
+ # vm_address_t address,
237
+ # vm_size_t size,
238
+ # vm_address_t *data_out,
239
+ # mach_msg_type_number_t *data_size);
240
+ #
241
+ # There is no man page for this function.
242
+ def vm_read(task, addr, sz=256)
243
+ buf = FFI::MemoryPointer.new(sz)
244
+ len = FFI::MemoryPointer(sz.to_l32)
245
+ r = Libc.vm_read_overwrite(task, addr, sz, buf, len)
246
+ raise KernelCallError.new(:vm_read, r) if r != 0
247
+ return buf.to_str(len.to_str(4).to_l32)
248
+ end
249
+
250
+ # Writes val to task's memory space at address addr.
251
+ # It is necessary for val.size to report the size of val in bytes
252
+ #
253
+ # kern_return_t vm_write
254
+ # (vm_task_t target_task,
255
+ # vm_address_t address,
256
+ # pointer_t data,
257
+ # mach_msg_type_number_t data_count);
258
+ #
259
+ # There is no man page for this function.
260
+ def vm_write(task, addr, val)
261
+ val = FFI::MemoryPointer.new
262
+ r = Libc.vm_write(task, addr, val, val.size)
263
+ raise KernelCallError.new(:vm_write, r) if r != 0
264
+ return nil
265
+ end
266
+
267
+ # Changes the protection state beginning at addr for size bytes to the mask prot.
268
+ # If setmax is true this will set the maximum permissions, otherwise it will set FIXME
269
+ #
270
+ # kern_return_t vm_protect
271
+ # (vm_task_t target_task,
272
+ # vm_address_t address,
273
+ # vm_size_t size,
274
+ # boolean_t set_maximum,
275
+ # vm_prot_t new_protection);
276
+ #
277
+ # There is no man page for this function.
278
+ def vm_protect(task, addr, size, setmax, prot)
279
+ setmax = setmax ? 1 : 0
280
+ r = Libc.vm_protect(task, addr, size, setmax, prot)
281
+ raise KernelCallError.new(:vm_protect, r) if r != 0
282
+ return nil
283
+ end
284
+
285
+ # Allocates a page in the memory space of the target task.
286
+ #
287
+ # kern_return_t vm_allocate
288
+ # (vm_task_t target_task,
289
+ # vm_address_t address,
290
+ # vm_size_t size,
291
+ # boolean_t anywhere);
292
+ #
293
+ def vm_allocate(task, address, size, anywhere)
294
+ addr = FFI::MemoryPointer.new :int, 1
295
+ addr.write_int(address)
296
+ anywhere = anywhere ? 1 : 0
297
+ r = Libc.vm_allocate(task, addr, size, anywhere)
298
+ raise KernelCallError.new(r) if r != 0
299
+ addr.address
300
+ end
301
+
302
+ # deallocates a page in the memoryspace of target task.
303
+ #
304
+ # kern_return_t vm_deallocate
305
+ # (vm_task_t target_task,
306
+ # vm_address_t address,
307
+ # vm_size_t size);
308
+ #
309
+ def vm_deallocate(task, address, size)
310
+ addr = FFI::MemoryPointer.new :int, 1
311
+ addr.write_int(address)
312
+ r = Libc.vm_deallocate(task, addr, size)
313
+ raise KernelCallError.new(r) if r != 0
314
+ end
315
+
316
+ # Resumes a suspended thread by id.
317
+ #
318
+ # kern_return_t thread_resume
319
+ # (thread_act_t target_thread);
320
+ #
321
+ # There is no man page for this function.
322
+ def thread_resume(thread)
323
+ r = Libc.thread_resume(thread)
324
+ raise KernelCallError.new(:thread_resume, r) if r != 0
325
+ end
326
+
327
+ # Suspends a thread by id.
328
+ #
329
+ # kern_return_t thread_suspend
330
+ # (thread_act_t target_thread);
331
+ #
332
+ # There is no man page for this function.
333
+ def thread_suspend(thread)
334
+ r = Libc.thread_suspend(thread)
335
+ raise KernelCallError.new(:thread_suspend, r) if r != 0
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
+ FFI.errno = 0
344
+ args.flatten!
345
+ argv = FFI::MemoryPointer.new(:pointer, args.size + 1)
346
+ args.each_with_index do |arg, i|
347
+ argv[i].put_pointer(0, FFI::MemoryPointer.from_string(arg.to_s))
348
+ end
349
+ argv[args.size].put_pointer(0, nil)
350
+
351
+ r = Libc.execv(path, argv)
352
+ # if this ever returns, there's been an error
353
+ raise SystemCallError(:execv, FFI.errno)
354
+ end
355
+ end
356
+ end
@@ -0,0 +1,60 @@
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 = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
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 function to load utility classes and extensions
36
+ def self.require_utils
37
+ %w{utils}.each{|r| require self.libpath(r)+'.rb'}
38
+ end
39
+
40
+ # Utility method used to require all files ending in .rb that lie in the
41
+ # directory below this file that has the same name as the filename passed
42
+ # in. Optionally, a specific _directory_ name can be passed in such that
43
+ # the _filename_ does not have to be equivalent to the directory.
44
+ #
45
+ def self.require_all_libs_relative_to( fname, dir = nil )
46
+ self.require_utils
47
+ dir ||= ::File.basename(fname, '.*')
48
+ search_me = ::File.expand_path(
49
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
50
+
51
+ Dir.glob(search_me).reject{|rb| rb =~ /#{__FILE__}/}.sort.each {|rb| require rb}
52
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
53
+
54
+ end
55
+ end # module Ragweed::Wraposx
56
+
57
+ require 'ragweed/wraposx/wraposx'
58
+ Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
59
+
60
+ # EOF