ragweed 0.1.7.3 → 0.2.0.pre1
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/README.rdoc +33 -8
- data/Rakefile +80 -23
- data/VERSION +1 -0
- data/examples/hittracertux.rb +2 -6
- data/examples/hook_notepad.rb +1 -1
- data/examples/tux-example.rb +3 -2
- data/lib/.DS_Store +0 -0
- data/lib/ragweed/debugger32.rb +188 -145
- data/lib/ragweed/debuggerosx.rb +13 -13
- data/lib/ragweed/debuggertux.rb +267 -140
- data/lib/ragweed/rasm.rb +1 -1
- data/lib/ragweed/wrap32/debugging.rb +184 -64
- data/lib/ragweed/wrap32/hooks.rb +27 -11
- data/lib/ragweed/wrap32/process.rb +114 -7
- data/lib/ragweed/wrap32/process_token.rb +23 -7
- data/lib/ragweed/wrap32/thread_context.rb +100 -166
- data/lib/ragweed/wrap32/wrap32.rb +127 -72
- data/lib/ragweed/wrap32.rb +1 -1
- data/lib/ragweed/wraposx/constants.rb +1 -9
- data/lib/ragweed/wraposx/region_info.rb +209 -188
- data/lib/ragweed/wraposx/structs.rb +102 -0
- data/lib/ragweed/wraposx/thread_context.rb +636 -159
- data/lib/ragweed/wraposx/thread_info.rb +40 -107
- data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
- data/lib/ragweed/wraposx/wraposx.rb +154 -231
- data/lib/ragweed/wraposx.rb +2 -1
- data/lib/ragweed/wraptux/constants.rb +46 -22
- data/lib/ragweed/wraptux/struct_helpers.rb +25 -0
- data/lib/ragweed/wraptux/threads.rb +0 -0
- data/lib/ragweed/wraptux/wraptux.rb +58 -62
- data/lib/ragweed/wraptux.rb +3 -4
- data/lib/ragweed.rb +36 -8
- data/ragweed.gemspec +85 -15
- metadata +50 -18
@@ -1,18 +1,5 @@
|
|
1
1
|
module Ragweed; end
|
2
2
|
module Ragweed::Wraposx::ThreadInfo
|
3
|
-
class << self
|
4
|
-
#factory method to get a ThreadInfo variant
|
5
|
-
def get(flavor,tid)
|
6
|
-
found = false
|
7
|
-
klass = self.constants.detect{|c| con = self.const_get(c); con.kind_of?(Class) && (flavor == con.const_get(:FLAVOR))}
|
8
|
-
if klass.nil?
|
9
|
-
raise Ragwed::Wraposx::KErrno::INVALID_ARGUMENT
|
10
|
-
else
|
11
|
-
klass.get(tid)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
3
|
# info interfaces
|
17
4
|
BASIC_INFO = 3 #basic information
|
18
5
|
|
@@ -22,17 +9,6 @@ module Ragweed::Wraposx::ThreadInfo
|
|
22
9
|
SCHED_RR_INFO = 11
|
23
10
|
# SCHED_FIFO_INFO = 12
|
24
11
|
|
25
|
-
FLAVORS = {
|
26
|
-
# define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
|
27
|
-
BASIC_INFO => {:size => 30, :count => 10},
|
28
|
-
# define POLICY_TIMESHARE_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_timeshare_info)/sizeof(integer_t)))
|
29
|
-
SCHED_TIMESHARE_INFO => {:size => 20, :count => 5},
|
30
|
-
# define POLICY_RR_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_rr_info)/sizeof(integer_t)))
|
31
|
-
SCHED_RR_INFO => {:size => 20,:count => 5},
|
32
|
-
# define POLICY_FIFO_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_fifo_info)/sizeof(integer_t)))
|
33
|
-
# SCHED_FIFO_INFO => {:size => 16,:count => 4} # immediately returns KERNEL_INVALID_POLICY on osx
|
34
|
-
}
|
35
|
-
|
36
12
|
module State
|
37
13
|
#Thread run states
|
38
14
|
RUNNING = 1 #/* thread is running normally */
|
@@ -42,46 +18,6 @@ module Ragweed::Wraposx::ThreadInfo
|
|
42
18
|
HALTED = 5 #/* thread is halted at a clean point */
|
43
19
|
end
|
44
20
|
|
45
|
-
module ThreadInfoMixins
|
46
|
-
def initialize(str=nil)
|
47
|
-
refresh(str) if (str && !str.empty?)
|
48
|
-
end
|
49
|
-
|
50
|
-
# (re)loads the data from str
|
51
|
-
def refresh(str)
|
52
|
-
fields = self.class.const_get :FIELDS
|
53
|
-
pp self.class
|
54
|
-
if str and not str.empty?
|
55
|
-
str.unpack(fields.map {|x| x[1]}.join("")).each_with_index do |val, i|
|
56
|
-
raise "i is nil" if i.nil?
|
57
|
-
instance_variable_set "@#{ fields[i][0] }".intern, val
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def to_s
|
63
|
-
fields = self.class.const_get :FIELDS
|
64
|
-
fields.map {|f| send(f[0])}.pack(fields.map {|x| x[1]}.join(""))
|
65
|
-
end
|
66
|
-
|
67
|
-
def inspect
|
68
|
-
body = lambda do
|
69
|
-
self.class.const_get(:FIELDS).map do |f|
|
70
|
-
"#{f[0]}=#{send(f[0]).to_s}"
|
71
|
-
end.join(", ")
|
72
|
-
end
|
73
|
-
"#<#{self.class.name.split('::').last(2).join('::')} #{body.call}>"
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.get(t)
|
77
|
-
self.new(Ragweed::Wraposx::thread_info_raw(t, self.class.const_get(:FLAVOR)))
|
78
|
-
end
|
79
|
-
|
80
|
-
def get(t)
|
81
|
-
refresh(Ragweed::Wraposx::vm_region_raw(t, self.class.const_get(:FLAVOR)))
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
21
|
# struct thread_basic_info
|
86
22
|
# {
|
87
23
|
# time_value_t user_time;
|
@@ -93,35 +29,23 @@ module Ragweed::Wraposx::ThreadInfo
|
|
93
29
|
# integer_t suspend_count;
|
94
30
|
# integer_t sleep_time;
|
95
31
|
# };
|
96
|
-
class Basic
|
97
|
-
include Ragweed::
|
32
|
+
class Basic < FFI::Struct
|
33
|
+
include Ragweed::FFIStructInclude
|
98
34
|
module Flags
|
99
35
|
#Thread flags (flags field).
|
100
36
|
SWAPPED = 0x1 #/* thread is swapped out */
|
101
37
|
IDLE = 0x2 #/* thread is an idle thread */
|
102
38
|
end
|
103
|
-
|
104
|
-
attr_accessor :user_time
|
105
|
-
attr_accessor :system_time
|
106
|
-
alias_method :__refresh, :refresh
|
107
|
-
(FIELDS = [ [:user_time_s, "I"],
|
108
|
-
[:user_time_us, "I"],
|
109
|
-
[:system_time_s, "I"],
|
110
|
-
[:system_time_us, "I"],
|
111
|
-
[:cpu_usage, "I"],
|
112
|
-
[:policy, "I"],
|
113
|
-
[:run_state, "I"],
|
114
|
-
[:flags, "I"],
|
115
|
-
[:suspend_count, "I"],
|
116
|
-
[:sleep_time, "I"]]).each {|x| attr_accessor x[0]}
|
117
39
|
|
118
40
|
FLAVOR = Ragweed::Wraposx::ThreadInfo::BASIC_INFO
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
125
49
|
|
126
50
|
def dump(&block)
|
127
51
|
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
@@ -150,13 +74,12 @@ EOM
|
|
150
74
|
# boolean_t depressed;
|
151
75
|
# int depress_priority;
|
152
76
|
# };
|
153
|
-
class SchedTimeshare
|
154
|
-
include Ragweed::
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
[:depress_priority, "I"]]).each {|x| attr_accessor x[0]}
|
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
|
160
83
|
|
161
84
|
def dump(&block)
|
162
85
|
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
@@ -181,13 +104,13 @@ EOM
|
|
181
104
|
# boolean_t depressed;
|
182
105
|
# int depress_priority;
|
183
106
|
# };
|
184
|
-
class SchedRr
|
185
|
-
include Ragweed::
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
191
114
|
|
192
115
|
def dump(&block)
|
193
116
|
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
@@ -201,8 +124,19 @@ EOM
|
|
201
124
|
depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
|
202
125
|
depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
|
203
126
|
EOM
|
127
|
+
end
|
204
128
|
end
|
205
|
-
|
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
|
+
}
|
206
140
|
end
|
207
141
|
|
208
142
|
module Ragweed::Wraposx
|
@@ -215,13 +149,12 @@ module Ragweed::Wraposx
|
|
215
149
|
# thread_flavor_t flavor,
|
216
150
|
# thread_info_t thread_info,
|
217
151
|
# mach_msg_type_number_t thread_info_count);
|
218
|
-
def
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
r = CALLS["libc!thread_info:IIPP=I"].call(thread,flavor,info,Ragweed::Wraposx::ThreadInfo::FLAVORS[flavor][:count]).first
|
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)
|
223
156
|
raise KernelCallError.new(r) if r != 0
|
224
|
-
|
157
|
+
ThreadInfo::FLAVORS[flavor][:class].new info
|
225
158
|
end
|
226
159
|
end
|
227
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
|