ragweed 0.2.1-java → 0.2.3-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.
- data/README.rdoc +4 -9
- data/VERSION +1 -1
- data/lib/ragweed/debuggerosx.rb +23 -14
- data/lib/ragweed/debuggertux.rb +63 -26
- data/lib/ragweed/wrap32/process_token.rb +6 -0
- data/lib/ragweed/wraposx/region_info.rb +12 -6
- data/lib/ragweed/wraposx/thread_context.rb +160 -49
- data/lib/ragweed/wraposx/wraposx.rb +14 -9
- data/lib/ragweed/wraptux/process.rb +2 -1
- data/ragweed.gemspec +4 -17
- metadata +4 -12
- data/lib/ragweed/wraposx/thread_info.rb.old +0 -121
data/README.rdoc
CHANGED
@@ -20,11 +20,10 @@ Ragweed is supported and has been tested on the following platforms (32bit intel
|
|
20
20
|
Mac OS X 10.6
|
21
21
|
Mac OS X 10.5
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
require significant changes to Ragweed.
|
23
|
+
Ragweed works with Ruby 1.8.7, 1.9.1 and 1.9.2 and should work with any Ruby that includes FFI support on 32bit WinXP, Win7, Linux 2.6 and OSX 10.6.
|
24
|
+
We are actively investigating 64 bit support for each platform. Unfortunately, this will require significant changes to Ragweed.
|
26
25
|
|
27
|
-
* We
|
26
|
+
* We have completed switching from Ruby/DL to FFI in 0.2.0. There should be no incompatibilities as a result of this switch. Additionally, ragweed may now work on rubies that include FFI support (jruby, ree, rbx), this has not yet been tested.
|
28
27
|
|
29
28
|
== FEATURES/PROBLEMS:
|
30
29
|
|
@@ -33,10 +32,6 @@ require significant changes to Ragweed.
|
|
33
32
|
|
34
33
|
* Work is ongoing to complete and unify the OSX and Linux portions.
|
35
34
|
|
36
|
-
* The FFI move is mostly complete. There may be a few changes to some structures to come, but everything should mostly match the C APIs.
|
37
|
-
|
38
|
-
* The move to FFI should give us free support for jRuby. This is, however, untested at this time.
|
39
|
-
|
40
35
|
* Struct's Nerve[http://github.com/struct/Nerve] is an example of the API we are heading toward
|
41
36
|
|
42
37
|
== SYNOPSIS:
|
@@ -57,4 +52,4 @@ Please see the examples directory for more. There are hit tracers for each platf
|
|
57
52
|
|
58
53
|
== LICENSE:
|
59
54
|
|
60
|
-
Copyright 2009
|
55
|
+
Copyright 2009-2011 Matasano Security, LLC All Rights Reserved
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
data/lib/ragweed/debuggerosx.rb
CHANGED
@@ -217,7 +217,7 @@ class Ragweed::Debuggerosx
|
|
217
217
|
on_attach
|
218
218
|
self.hook(opts) if (opts[:hook] and not @hooked)
|
219
219
|
self.install_bps if (opts[:install] and not @installed)
|
220
|
-
return r
|
220
|
+
return r.first
|
221
221
|
end
|
222
222
|
|
223
223
|
# remove breakpoints and release child
|
@@ -229,7 +229,7 @@ class Ragweed::Debuggerosx
|
|
229
229
|
@attached = false
|
230
230
|
on_detach
|
231
231
|
self.unhook(opts) if opts[:hook] and @hooked
|
232
|
-
return r
|
232
|
+
return r.first
|
233
233
|
end
|
234
234
|
|
235
235
|
# get task port for @pid and store in @task so mach calls can be made
|
@@ -253,14 +253,14 @@ class Ragweed::Debuggerosx
|
|
253
253
|
# resumes thread that has been suspended via thread_suspend
|
254
254
|
# thread: thread id of thread to be resumed
|
255
255
|
def resume(thread = nil)
|
256
|
-
thread
|
256
|
+
thread ||= self.threads.first)
|
257
257
|
Ragweed::Wraposx::thread_resume(thread)
|
258
258
|
end
|
259
259
|
|
260
260
|
# suspends thread
|
261
261
|
# thread: thread id of thread to be suspended
|
262
262
|
def suspend(thread = nil)
|
263
|
-
thread
|
263
|
+
thread ||= self.threads.first)
|
264
264
|
Ragweed::Wraposx::thread_suspend(thread)
|
265
265
|
end
|
266
266
|
|
@@ -359,16 +359,17 @@ class Ragweed::Debuggerosx
|
|
359
359
|
# returns a Ragweed::Wraposx::ThreadContext object containing the register states
|
360
360
|
# thread: thread to get the register state of
|
361
361
|
def get_registers(thread=nil)
|
362
|
-
thread
|
363
|
-
Ragweed::Wraposx
|
362
|
+
thread ||= self.threads.first)
|
363
|
+
Ragweed::Wraposx.thread_get_state(thread, Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE)
|
364
364
|
end
|
365
365
|
|
366
366
|
# sets the register state of a thread
|
367
367
|
# thread: thread id to set registers for
|
368
368
|
# regs: Ragweed::Wraposx::ThreadContext object containing the new register state for the thread
|
369
369
|
def set_registers(thread, regs)
|
370
|
-
|
371
|
-
|
370
|
+
# XXX - needs updated conditions
|
371
|
+
# raise "Must supply registers and thread to set" if (not (thread and regs) or not thread.kind_of? Numeric or not regs.kind_of? Ragweed::Wraposx::ThreadContext)
|
372
|
+
Ragweed::Wraposx.thread_set_state(thread, regs.class::FLAVOR, regs)
|
372
373
|
end
|
373
374
|
|
374
375
|
# continue stopped child process.
|
@@ -400,18 +401,26 @@ class Ragweed::Debuggerosx
|
|
400
401
|
def installed?; @installed; end
|
401
402
|
|
402
403
|
def region_info(addr, flavor = :basic)
|
403
|
-
case flavor
|
404
|
+
flav = case flavor
|
404
405
|
when :basic
|
405
|
-
|
406
|
+
Ragweed::Wraposx::Vm::RegionBasicInfo::FLAVOR
|
406
407
|
|
407
408
|
# Extended and Top info flavors are included in case Apple re implements them
|
408
409
|
when :extended
|
409
|
-
|
410
|
+
Ragweed::Wraposx::Vm::RegionExtendedInfo::FLAVOR
|
410
411
|
when :top
|
411
|
-
|
412
|
+
Ragweed::Wraposx::Vm::RegionTopInfo::FLAVOR
|
413
|
+
when Integer
|
414
|
+
flavor
|
412
415
|
else
|
413
416
|
warn "Unknown flavor requested. Returning RegionBasicInfo."
|
414
|
-
|
417
|
+
Ragweed::Wraposx::RegionBasicInfo::FLAVOR
|
418
|
+
end
|
419
|
+
|
420
|
+
if Ragweed::Wraposx.respond_to? :vm_region_64
|
421
|
+
Ragweed::Wraposx.vm_region_64(@task, addr, flav)
|
422
|
+
else
|
423
|
+
Ragweed::Wraposx.vm_region(@task, addr, flav)
|
415
424
|
end
|
416
425
|
end
|
417
426
|
|
@@ -428,7 +437,7 @@ class Ragweed::Debuggerosx
|
|
428
437
|
first
|
429
438
|
if exact && (rtype == name || purpose == name)
|
430
439
|
ret << [saddr, eaddr].map{|x| x.to_i(16)}
|
431
|
-
elsif rtype.match(name) || purpose.match(name)
|
440
|
+
elsif rtype && purpose && (rtype.match(name) || purpose.match(name))
|
432
441
|
ret << [saddr, eaddr].map{|x| x.to_i(16)}
|
433
442
|
end
|
434
443
|
end
|
data/lib/ragweed/debuggertux.rb
CHANGED
@@ -13,7 +13,7 @@ module Ragweed; end
|
|
13
13
|
## that Debuggertux already handles, call "super", too.
|
14
14
|
class Ragweed::Debuggertux
|
15
15
|
attr_reader :pid, :status, :exited, :signal
|
16
|
-
attr_accessor :breakpoints, :mapped_regions, :process
|
16
|
+
attr_accessor :breakpoints, :mapped_regions, :process, :use_ptrace_for_search
|
17
17
|
|
18
18
|
## Class to handle installing/uninstalling breakpoints
|
19
19
|
class Breakpoint
|
@@ -74,6 +74,7 @@ class Ragweed::Debuggertux
|
|
74
74
|
default_opts(opts)
|
75
75
|
@installed = false
|
76
76
|
@attached = false
|
77
|
+
@use_ptrace_for_search = false
|
77
78
|
|
78
79
|
@mapped_regions = Hash.new
|
79
80
|
@breakpoints = Hash.new
|
@@ -132,7 +133,6 @@ class Ragweed::Debuggertux
|
|
132
133
|
## value = Size of the region
|
133
134
|
def mapped
|
134
135
|
@mapped_regions.clear if @mapped_regions
|
135
|
-
|
136
136
|
File.open("/proc/#{pid}/maps") do |f|
|
137
137
|
f.each_line do |l|
|
138
138
|
e = l.split(' ',2).first
|
@@ -209,9 +209,7 @@ class Ragweed::Debuggertux
|
|
209
209
|
lib = l.split(' ', 6)
|
210
210
|
sa = l.split('-', 0)
|
211
211
|
|
212
|
-
if lib[5] =~ /vdso/
|
213
|
-
next
|
214
|
-
end
|
212
|
+
next if lib[5] =~ /vdso/
|
215
213
|
|
216
214
|
lib = lib[5].strip
|
217
215
|
lib.gsub!(/[\s\n]+/, "")
|
@@ -229,50 +227,89 @@ class Ragweed::Debuggertux
|
|
229
227
|
end
|
230
228
|
|
231
229
|
## Search a specific page for a value
|
232
|
-
## Should be used by most
|
233
|
-
def search_page(base, max, val)
|
234
|
-
loc =
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
230
|
+
## Should be used by most search methods
|
231
|
+
def search_page(base, max, val, &block)
|
232
|
+
loc = []
|
233
|
+
if self.use_ptrace_for_search == true
|
234
|
+
while base.to_i < max.to_i
|
235
|
+
r = Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, base, 0)
|
236
|
+
loc << base if r == val
|
237
|
+
base += 4
|
238
|
+
yield loc if block_given?
|
239
|
+
end
|
240
|
+
else
|
241
|
+
sz = max.to_i - base.to_i
|
242
|
+
d = File.new("/proc/#{pid}/mem")
|
243
|
+
d.seek(base.to_i, IO::SEEK_SET)
|
244
|
+
b = d.read(sz)
|
245
|
+
i = 0
|
246
|
+
while(i < sz)
|
247
|
+
if val == b[i,4].unpack('L')
|
248
|
+
loc << base.to_i + i
|
249
|
+
yield(base.to_i + i) if block_given?
|
250
|
+
end
|
251
|
+
i += 4
|
240
252
|
end
|
241
|
-
|
253
|
+
d.close
|
242
254
|
end
|
243
255
|
|
244
256
|
loc
|
245
257
|
end
|
246
258
|
|
247
|
-
|
248
|
-
|
249
|
-
loc = Array.new
|
259
|
+
def search_mem_by_name(name, val, &block)
|
260
|
+
loc = []
|
250
261
|
File.open("/proc/#{pid}/maps") do |f|
|
251
262
|
f.each_line do |l|
|
252
|
-
if l =~ /\[
|
263
|
+
if l =~ /\[#{name}\]/
|
253
264
|
s,e = l.split('-')
|
254
265
|
e = e.split(' ').first
|
255
266
|
s = s.to_i(16)
|
256
267
|
e = e.to_i(16)
|
257
268
|
sz = e - s
|
258
269
|
max = s + sz
|
259
|
-
loc
|
270
|
+
loc << search_page(s, max, val, &block)
|
260
271
|
end
|
261
272
|
end
|
262
273
|
end
|
263
|
-
loc
|
274
|
+
loc
|
275
|
+
end
|
276
|
+
|
277
|
+
def search_mem_by_permission(perm, val, &block)
|
278
|
+
loc = []
|
279
|
+
File.open("/proc/#{pid}/maps") do |f|
|
280
|
+
f.each_line do |l|
|
281
|
+
if l.split(' ')[1] =~ /#{perm}/
|
282
|
+
s,e = l.split('-')
|
283
|
+
e = e.split(' ').first
|
284
|
+
s = s.to_i(16)
|
285
|
+
e = e.to_i(16)
|
286
|
+
sz = e - s
|
287
|
+
max = s + sz
|
288
|
+
loc << search_page(s, max, val, &block)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
loc
|
293
|
+
end
|
294
|
+
|
295
|
+
## Search the heap for a value, returns an array of matches
|
296
|
+
def search_heap(val, &block)
|
297
|
+
search_mem_by_name('heap', &block)
|
298
|
+
end
|
299
|
+
|
300
|
+
## Search the stack for a value, returns an array of matches
|
301
|
+
def search_stack(val, &block)
|
302
|
+
search_mem_by_name('stack', &block)
|
264
303
|
end
|
265
304
|
|
266
305
|
## Search all mapped regions for a value
|
267
|
-
def search_process(val)
|
268
|
-
loc =
|
306
|
+
def search_process(val, &block)
|
307
|
+
loc = []
|
269
308
|
self.mapped
|
270
309
|
@mapped_regions.each_pair do |k,v|
|
271
|
-
if k == 0 or v == 0
|
272
|
-
next
|
273
|
-
end
|
310
|
+
next if k == 0 or v == 0
|
274
311
|
max = k+v
|
275
|
-
loc
|
312
|
+
loc << search_page(k, max, val, &block)
|
276
313
|
end
|
277
314
|
loc
|
278
315
|
end
|
@@ -27,6 +27,7 @@ module Ragweed::Wrap32
|
|
27
27
|
ffi_convention :stdcall
|
28
28
|
attach_function 'OpenProcess', [ :long, :long, :long ], :long
|
29
29
|
attach_function 'OpenProcessToken', [:long, :long, :pointer ], :long
|
30
|
+
attach_function 'TerminateProcess', [:long, :uint], :long
|
30
31
|
|
31
32
|
# ffi_lib 'advapi32'
|
32
33
|
# ffi_convention :stdcall
|
@@ -60,6 +61,11 @@ module Ragweed::Wrap32
|
|
60
61
|
outw.read_long_long
|
61
62
|
end
|
62
63
|
end
|
64
|
+
|
65
|
+
def terminate_process(handle, exit_code)
|
66
|
+
r = Win.TerminateProcess(handle, exit_code)
|
67
|
+
raise WinX.new(:terminate_process) if r != 0
|
68
|
+
end
|
63
69
|
end
|
64
70
|
|
65
71
|
class Ragweed::Wrap32::ProcessToken
|
@@ -39,6 +39,7 @@ module Ragweed::Wraposx::Vm
|
|
39
39
|
end
|
40
40
|
|
41
41
|
class RegionBasicInfo < RegionInfo
|
42
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO
|
42
43
|
|
43
44
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
44
45
|
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
@@ -73,6 +74,7 @@ EOM
|
|
73
74
|
end
|
74
75
|
|
75
76
|
class RegionBasicInfo64 < RegionInfo
|
77
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO_64
|
76
78
|
|
77
79
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
78
80
|
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
@@ -118,6 +120,8 @@ EOM
|
|
118
120
|
# unsigned char share_mode;
|
119
121
|
# };
|
120
122
|
class RegionExtendedInfo < RegionInfo
|
123
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_EXTENDED_INFO
|
124
|
+
|
121
125
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
122
126
|
:user_tag, :uint,
|
123
127
|
:pages_resident, :uint,
|
@@ -161,6 +165,8 @@ EOM
|
|
161
165
|
# unsigned char share_mode;
|
162
166
|
# };
|
163
167
|
class RegionTopInfo < RegionInfo
|
168
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_TOP_INFO
|
169
|
+
|
164
170
|
layout :obj_id, :uint,
|
165
171
|
:ref_count, :uint,
|
166
172
|
:private_pages_resident, :uint,
|
@@ -230,9 +236,9 @@ module Ragweed::Wraposx
|
|
230
236
|
def vm_region(task, addr, flavor)
|
231
237
|
info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class], 1)
|
232
238
|
count = FFI::MemoryPointer.new(:int, 1).write_int(Vm::FLAVORS[flavor][:count])
|
233
|
-
address = FFI::MemoryPointer.new(:vm_address_t, 1).write_ulong(addr)
|
234
|
-
sz = FFI::MemoryPointer.new(:vm_size_t, 1)
|
235
|
-
objn = FFI::MemoryPointer.new(:mach_port_t, 1)
|
239
|
+
address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr)
|
240
|
+
sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1)
|
241
|
+
objn = FFI::MemoryPointer.new(Libc.find_type(:mach_port_t), 1)
|
236
242
|
|
237
243
|
r = Libc.vm_region(task, address, sz, flavor, info, count, objn)
|
238
244
|
raise KernelCallError.new(:vm_region, r) if r != 0
|
@@ -258,7 +264,7 @@ module Ragweed::Wraposx
|
|
258
264
|
def vm_region_64(task, addr, flavor)
|
259
265
|
# OSX does this as well, so we need to do it ourselves
|
260
266
|
flavor = Vm::REGION_BASIC_INFO_64 if flavor == Vm::REGION_BASIC_INFO
|
261
|
-
info = FFI::MemoryPointer.new(
|
267
|
+
info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class])
|
262
268
|
count = FFI::MemoryPointer.new(Libc.find_type(:mach_msg_type_number_t), 1).write_uint(Vm::FLAVORS[flavor][:count])
|
263
269
|
address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr)
|
264
270
|
sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1)
|
@@ -266,8 +272,8 @@ module Ragweed::Wraposx
|
|
266
272
|
|
267
273
|
r = Libc.vm_region_64(task, address, sz, flavor, info, count, objn)
|
268
274
|
raise KernelCallError.new(:vm_region_64, r) if r != 0
|
269
|
-
ret = Vm::
|
270
|
-
ret.region_size =
|
275
|
+
ret = Vm::FLAVORS[flavor][:class].new info
|
276
|
+
ret.region_size = sz.read_ulong
|
271
277
|
ret.base_address = address.read_ulong
|
272
278
|
ret
|
273
279
|
end if Libc.find_function "vm_region_64"
|
@@ -34,6 +34,14 @@ module Ragweed::Wraposx::ThreadContext
|
|
34
34
|
I386_FLOAT_STATE = X86_FLOAT_STATE32
|
35
35
|
I386_EXCEPTION_STATE = X86_EXCEPTION_STATE32
|
36
36
|
|
37
|
+
def self.get(thread, flavor = X86_THREAD_STATE)
|
38
|
+
Ragweed::Wraposx.thread_get_state(thread, flavor)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.set(thread, state)
|
42
|
+
Ragweed::Wraposx.thread_set_state(thread, state.class::FLAVOR, state)
|
43
|
+
end
|
44
|
+
|
37
45
|
# struct x86_state_hdr {
|
38
46
|
# int flavor;
|
39
47
|
# int count;
|
@@ -42,6 +50,20 @@ module Ragweed::Wraposx::ThreadContext
|
|
42
50
|
include Ragweed::FFIStructInclude
|
43
51
|
layout :flavor, :int,
|
44
52
|
:count, :int
|
53
|
+
def is_64?
|
54
|
+
case self[:flavor]
|
55
|
+
when 1, 2, 3, 10
|
56
|
+
false
|
57
|
+
when 4, 5, 6, 11
|
58
|
+
true
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def is_32?
|
65
|
+
!is_64?
|
66
|
+
end
|
45
67
|
end
|
46
68
|
|
47
69
|
# _STRUCT_X86_THREAD_STATE32
|
@@ -186,7 +208,7 @@ EOM
|
|
186
208
|
:rflags, :uint64,
|
187
209
|
:cs, :uint64,
|
188
210
|
:fs, :uint64,
|
189
|
-
:gs, :uint64
|
211
|
+
:gs, :uint64
|
190
212
|
|
191
213
|
module Flags
|
192
214
|
CARRY = 0x1
|
@@ -220,16 +242,16 @@ EOM
|
|
220
242
|
string =<<EOM
|
221
243
|
-----------------------------------------------------------------------
|
222
244
|
CONTEXT:
|
223
|
-
RIP: #{self.rip.to_s(16).rjust(16, "0")} #{maybe_dis.call(self.
|
224
|
-
|
225
|
-
RAX: #{self.rax.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
226
|
-
RBX: #{self.rbx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
227
|
-
RCX: #{self.rcx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
228
|
-
RDX: #{self.rdx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
229
|
-
RDI: #{self.rdi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
230
|
-
RSI: #{self.rsi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
231
|
-
RBP: #{self.rbp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
232
|
-
RSP: #{self.rsp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
245
|
+
RIP: #{self.rip.to_s(16).rjust(16, "0")} #{maybe_dis.call(self.rip)}
|
246
|
+
|
247
|
+
RAX: #{self.rax.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rax)}
|
248
|
+
RBX: #{self.rbx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rbx)}
|
249
|
+
RCX: #{self.rcx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rcx)}
|
250
|
+
RDX: #{self.rdx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rdx)}
|
251
|
+
RDI: #{self.rdi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rdi)}
|
252
|
+
RSI: #{self.rsi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rsi)}
|
253
|
+
RBP: #{self.rbp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rbp)}
|
254
|
+
RSP: #{self.rsp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rsp)}
|
233
255
|
RFL: #{(self.rflags & 0xffffffff).to_s(2).rjust(32, "0")} #{Flags.flag_dump(self.rflags & 0xffffffff)}
|
234
256
|
EOM
|
235
257
|
end
|
@@ -256,6 +278,10 @@ EOM
|
|
256
278
|
layout :tsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
257
279
|
:uts, Ragweed::Wraposx::ThreadContext::UnionThreadState
|
258
280
|
|
281
|
+
def is_64?; self[:tsh].is_64?; end
|
282
|
+
def is_32?; !is_64?; end
|
283
|
+
def header; self[:fsh]; end
|
284
|
+
|
259
285
|
# We have rubified this FFI structure by creating a bunch of proxy
|
260
286
|
# methods that are normally only accessible via self.v.x.y which is
|
261
287
|
# a lot to type. You can still use that method however these proxy
|
@@ -264,11 +290,11 @@ EOM
|
|
264
290
|
def methods regular=true
|
265
291
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
266
292
|
ret += self[:tsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
267
|
-
ret
|
293
|
+
ret += case self[:tsh][:flavor]
|
268
294
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
269
|
-
self[:uts]
|
295
|
+
self[:uts][:ts32].members.map{|x| [x.to_s, x.to_s + "="]}
|
270
296
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
271
|
-
self[:uts]
|
297
|
+
self[:uts][:ts64].members.map{|x| [x.to_s, x.to_s + "="]}
|
272
298
|
else
|
273
299
|
[]
|
274
300
|
end
|
@@ -278,11 +304,11 @@ EOM
|
|
278
304
|
def methods regular=true
|
279
305
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
280
306
|
ret += self[:tsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
281
|
-
ret
|
307
|
+
ret += case self[:tsh][:flavor]
|
282
308
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
283
|
-
self[:uts]
|
309
|
+
self[:uts][:ts32].members.map{|x| [x, (x.to_s + "=").intern]}
|
284
310
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
285
|
-
self[:uts]
|
311
|
+
self[:uts][:ts64].members.map{|x| [x, (x.to_s + "=").intern]}
|
286
312
|
else
|
287
313
|
[]
|
288
314
|
end
|
@@ -302,9 +328,9 @@ EOM
|
|
302
328
|
else
|
303
329
|
case self[:tsh][:flavor]
|
304
330
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
305
|
-
self[:uts]
|
331
|
+
self[:uts][:ts32].__send__(:[]=, mth, *args)
|
306
332
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
307
|
-
self[:uts]
|
333
|
+
self[:uts][:ts64].__send__(:[]=, mth, *args)
|
308
334
|
end
|
309
335
|
end
|
310
336
|
else
|
@@ -316,9 +342,9 @@ EOM
|
|
316
342
|
else
|
317
343
|
case self[:tsh][:flavor]
|
318
344
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
319
|
-
self[:uts]
|
345
|
+
self[:uts][:ts32].__send__(:[], meth, *args)
|
320
346
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
321
|
-
self[:uts]
|
347
|
+
self[:uts][:ts64].__send__(:[], meth, *args)
|
322
348
|
end
|
323
349
|
end
|
324
350
|
end
|
@@ -427,6 +453,10 @@ EOM
|
|
427
453
|
layout :dsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
428
454
|
:uds, Ragweed::Wraposx::ThreadContext::UnionDebugState
|
429
455
|
|
456
|
+
def is_64?; self[:dsh].is_64?; end
|
457
|
+
def is_32?; !is_64?; end
|
458
|
+
def header; self[:dsh]; end
|
459
|
+
|
430
460
|
# We have rubified this FFI structure by creating a bunch of proxy
|
431
461
|
# methods that are normally only accessible via self.v.x.y which is
|
432
462
|
# a lot to type. You can still use that method however these proxy
|
@@ -435,11 +465,11 @@ EOM
|
|
435
465
|
def methods regular=true
|
436
466
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
437
467
|
ret += self[:dsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
438
|
-
ret
|
468
|
+
ret += case self[:dsh][:flavor]
|
439
469
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
440
|
-
self[:uds]
|
470
|
+
self[:uds][:ds32].members.map{|x| [x.to_s, x.to_s + "="]}
|
441
471
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
442
|
-
self[:uds]
|
472
|
+
self[:uds][:ds64].members.map{|x| [x.to_s, x.to_s + "="]}
|
443
473
|
else
|
444
474
|
[]
|
445
475
|
end
|
@@ -449,11 +479,11 @@ EOM
|
|
449
479
|
def methods regular=true
|
450
480
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
451
481
|
ret += self[:dsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
452
|
-
ret
|
482
|
+
ret += case self[:dsh][:flavor]
|
453
483
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
454
|
-
self[:uds]
|
484
|
+
self[:uds][:ds32].members.map{|x| [x, (x.to_s + "=").intern]}
|
455
485
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
456
|
-
self[:uds]
|
486
|
+
self[:uds][:ds64].members.map{|x| [x, (x.to_s + "=").intern]}
|
457
487
|
else
|
458
488
|
[]
|
459
489
|
end
|
@@ -473,9 +503,9 @@ EOM
|
|
473
503
|
else
|
474
504
|
case self[:dsh][:flavor]
|
475
505
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
476
|
-
self[:uds]
|
506
|
+
self[:uds][:ds32].__send__(:[]=, mth, *args)
|
477
507
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
478
|
-
self[:uds]
|
508
|
+
self[:uds][:ds64].__send__(:[]=, mth, *args)
|
479
509
|
end
|
480
510
|
end
|
481
511
|
else
|
@@ -487,9 +517,9 @@ EOM
|
|
487
517
|
else
|
488
518
|
case self[:dsh][:flavor]
|
489
519
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
490
|
-
self[:uds]
|
520
|
+
self[:uds][:ds32].__send__(:[], meth, *args)
|
491
521
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
492
|
-
self[:uds]
|
522
|
+
self[:uds][:ds64].__send__(:[], meth, *args)
|
493
523
|
end
|
494
524
|
end
|
495
525
|
end
|
@@ -567,7 +597,11 @@ EOM
|
|
567
597
|
layout :esh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
568
598
|
:ues, Ragweed::Wraposx::ThreadContext::UnionExceptionState
|
569
599
|
|
570
|
-
|
600
|
+
|
601
|
+
def is_64?; self[:esh].is_64?; end
|
602
|
+
def is_32?; !is_64?; end
|
603
|
+
def header; self[:esh]; end
|
604
|
+
|
571
605
|
# We have rubified this FFI structure by creating a bunch of proxy
|
572
606
|
# methods that are normally only accessible via self.v.x.y which is
|
573
607
|
# a lot to type. You can still use that method however these proxy
|
@@ -576,11 +610,11 @@ EOM
|
|
576
610
|
def methods regular=true
|
577
611
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
578
612
|
ret += self[:esh].members.map{|x| [x.to_s, x.to_s + "="]}
|
579
|
-
ret
|
613
|
+
ret += case self[:esh][:flavor]
|
580
614
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
581
|
-
self[:ues]
|
615
|
+
self[:ues][:es32].members.map{|x| [x.to_s, x.to_s + "="]}
|
582
616
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
583
|
-
self[:ues]
|
617
|
+
self[:ues][:es64].members.map{|x| [x.to_s, x.to_s + "="]}
|
584
618
|
else
|
585
619
|
[]
|
586
620
|
end
|
@@ -590,11 +624,11 @@ EOM
|
|
590
624
|
def methods regular=true
|
591
625
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
592
626
|
ret += self[:esh].members.map{|x| [x, (x.to_s + "=").intern]}
|
593
|
-
ret
|
627
|
+
ret += case self[:esh][:flavor]
|
594
628
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
595
|
-
self[:ues]
|
629
|
+
self[:ues][:es32].members.map{|x| [x, (x.to_s + "=").intern]}
|
596
630
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
597
|
-
self[:ues]
|
631
|
+
self[:ues][:es64].members.map{|x| [x, (x.to_s + "=").intern]}
|
598
632
|
else
|
599
633
|
[]
|
600
634
|
end
|
@@ -614,9 +648,9 @@ EOM
|
|
614
648
|
else
|
615
649
|
case self[:esh][:flavor]
|
616
650
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
617
|
-
self[:ues]
|
651
|
+
self[:ues][:es32].__send__(:[]=, mth, *args)
|
618
652
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
619
|
-
self[:ues]
|
653
|
+
self[:ues][:es64].__send__(:[]=, mth, *args)
|
620
654
|
end
|
621
655
|
end
|
622
656
|
else
|
@@ -628,9 +662,9 @@ EOM
|
|
628
662
|
else
|
629
663
|
case self[:esh][:flavor]
|
630
664
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
631
|
-
self[:ues]
|
665
|
+
self[:ues][:es32].__send__(:[], meth, *args)
|
632
666
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
633
|
-
self[:ues]
|
667
|
+
self[:ues][:es64].__send__(:[], meth, *args)
|
634
668
|
end
|
635
669
|
end
|
636
670
|
end
|
@@ -843,6 +877,83 @@ EOM
|
|
843
877
|
FLAVOR = 8
|
844
878
|
layout :fsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
845
879
|
:ufs, Ragweed::Wraposx::ThreadContext::UnionFloatState
|
880
|
+
|
881
|
+
def is_64?; self[:fsh].is_64?; end
|
882
|
+
def is_32?; !is_64?; end
|
883
|
+
def header; self[:fsh]; end
|
884
|
+
|
885
|
+
# We have rubified this FFI structure by creating a bunch of proxy
|
886
|
+
# methods that are normally only accessible via self.v.x.y which is
|
887
|
+
# a lot to type. You can still use that method however these proxy
|
888
|
+
# methods should allow for considerably clearer code
|
889
|
+
if RUBY_VERSION < "1.9"
|
890
|
+
def methods regular=true
|
891
|
+
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
892
|
+
ret += self[:fsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
893
|
+
ret += case self[:fsh][:flavor]
|
894
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE32
|
895
|
+
self[:ufs][:fs32].members.map{|x| [x.to_s, x.to_s + "="]}
|
896
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE64
|
897
|
+
self[:ufs][:fs64].members.map{|x| [x.to_s, x.to_s + "="]}
|
898
|
+
else
|
899
|
+
[]
|
900
|
+
end
|
901
|
+
ret.flatten
|
902
|
+
end
|
903
|
+
else
|
904
|
+
def methods regular=true
|
905
|
+
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
906
|
+
ret += self[:fsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
907
|
+
ret += case self[:fsh][:flavor]
|
908
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE32
|
909
|
+
self[:ufs][:fs32].members.map{|x| [x, (x.to_s + "=").intern]}
|
910
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE64
|
911
|
+
self[:ufs][:fs64].members.map{|x| [x, (x.to_s + "=").intern]}
|
912
|
+
else
|
913
|
+
[]
|
914
|
+
end
|
915
|
+
ret.flatten
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
def method_missing meth, *args
|
920
|
+
super unless self.respond_to? meth
|
921
|
+
if meth.to_s =~ /=$/
|
922
|
+
mth = meth.to_s.gsub(/=$/,'').intern
|
923
|
+
if self.members.include? mth
|
924
|
+
# don't proxy
|
925
|
+
self.__send__(:[]=, mth, *args)
|
926
|
+
elsif self[:fsh].members.include? meth
|
927
|
+
self[:fsh].__send__(:[]=, mth, *args)
|
928
|
+
else
|
929
|
+
case self[:fsh][:flavor]
|
930
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
931
|
+
self[:ufs][:fs32].__send__(:[]=, mth, *args)
|
932
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
933
|
+
self[:ufs][:fs64].__send__(:[]=, mth, *args)
|
934
|
+
end
|
935
|
+
end
|
936
|
+
else
|
937
|
+
if self.members.include? meth
|
938
|
+
# don't proxy
|
939
|
+
self.__send__(:[], meth, *args)
|
940
|
+
elsif self[:fsh].members.include? meth
|
941
|
+
self[:fsh].__send__(:[], meth, *args)
|
942
|
+
else
|
943
|
+
case self[:fsh][:flavor]
|
944
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
945
|
+
self[:ufs][:fs32].__send__(:[], meth, *args)
|
946
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
947
|
+
self[:ufs][:fs64].__send__(:[], meth, *args)
|
948
|
+
end
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def respond_to? meth, include_priv=false
|
954
|
+
mth = meth.to_s.gsub(/=$/,'') # may not be needed anymore
|
955
|
+
self.methods.include? mth || super
|
956
|
+
end
|
846
957
|
end
|
847
958
|
|
848
959
|
FLAVORS = {
|
@@ -866,7 +977,7 @@ module Ragweed::Wraposx
|
|
866
977
|
module Libc
|
867
978
|
extend FFI::Library
|
868
979
|
ffi_lib FFI::Library::LIBC
|
869
|
-
attach_function :thread_get_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :
|
980
|
+
attach_function :thread_get_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :pointer], :kern_return_t
|
870
981
|
attach_function :thread_set_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :mach_msg_type_number_t], :kern_return_t
|
871
982
|
end
|
872
983
|
|
@@ -877,13 +988,13 @@ module Ragweed::Wraposx
|
|
877
988
|
# (thread_act_t target_thread,
|
878
989
|
# thread_state_flavor_t flavor,
|
879
990
|
# thread_state_t old_state,
|
880
|
-
# mach_msg_type_number_t old_state_count);
|
991
|
+
# mach_msg_type_number_t *old_state_count);
|
881
992
|
def thread_get_state(thread,flavor)
|
882
|
-
state = FFI::MemoryPointer.new Ragweed::Wraposx::ThreadContext::
|
883
|
-
count = FFI::MemoryPointer.new(:int, 1).
|
993
|
+
state = FFI::MemoryPointer.new Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class]
|
994
|
+
count = FFI::MemoryPointer.new(:int, 1).write_uint Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:count]
|
884
995
|
r = Libc.thread_get_state(thread, flavor, state, count)
|
885
996
|
raise KernelCallError.new(:thread_get_state, r) if r != 0
|
886
|
-
Ragweed::Wraposx::ThreadContext::
|
997
|
+
Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state
|
887
998
|
end
|
888
999
|
|
889
1000
|
# Sets the register state of thread.
|
@@ -892,11 +1003,11 @@ module Ragweed::Wraposx
|
|
892
1003
|
# (thread_act_t target_thread,
|
893
1004
|
# thread_state_flavor_t flavor,
|
894
1005
|
# thread_state_t new_state,
|
895
|
-
#
|
1006
|
+
# mach_msg_type_number_t new_state_count);
|
896
1007
|
def thread_set_state(thread, flavor, state)
|
897
1008
|
r = Libc.thread_set_state(thread, flavor, state.to_ptr, ThreadContext::FLAVORS[flavor][:count])
|
898
1009
|
raise KernelCallError.new(:thread_set_state, r) if r!= 0
|
899
|
-
Ragweed::Wraposx::ThreadContext::
|
1010
|
+
Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state
|
900
1011
|
end
|
901
1012
|
end
|
902
1013
|
end
|
@@ -178,10 +178,10 @@ module Ragweed::Wraposx
|
|
178
178
|
# There is no man page for this call.
|
179
179
|
def task_for_pid(pid, target=nil)
|
180
180
|
target ||= mach_task_self
|
181
|
-
port = FFI::MemoryPointer.new :
|
181
|
+
port = FFI::MemoryPointer.new :uint, 1
|
182
182
|
r = Libc.task_for_pid(target, pid, port)
|
183
183
|
raise KernelCallError.new(:task_for_pid, r) if r != 0
|
184
|
-
port.
|
184
|
+
port.read_uint
|
185
185
|
end
|
186
186
|
|
187
187
|
# Returns an Array of thread IDs for the given task
|
@@ -193,11 +193,11 @@ module Ragweed::Wraposx
|
|
193
193
|
#
|
194
194
|
#There is no man page for this funtion.
|
195
195
|
def task_threads(port)
|
196
|
-
threads = FFI::MemoryPointer.new :
|
196
|
+
threads = FFI::MemoryPointer.new :pointer, 1
|
197
197
|
count = FFI::MemoryPointer.new :int, 1
|
198
198
|
r = Libc.task_threads(port, threads, count)
|
199
199
|
raise KernelCallError.new(:task_threads, r) if r != 0
|
200
|
-
threads.
|
200
|
+
threads.read_pointer.read_array_of_uint(count.read_uint)
|
201
201
|
end
|
202
202
|
|
203
203
|
# Decrement the target tasks suspend count
|
@@ -215,6 +215,7 @@ module Ragweed::Wraposx
|
|
215
215
|
def task_suspend(task)
|
216
216
|
r = Libc.task_suspend(task)
|
217
217
|
raise KernelCallError.new(r) if r != 0
|
218
|
+
r
|
218
219
|
end
|
219
220
|
|
220
221
|
# Sends a signal to a process
|
@@ -227,6 +228,7 @@ module Ragweed::Wraposx
|
|
227
228
|
FFI::errno = 0
|
228
229
|
r = Libc.kill(pid, sig)
|
229
230
|
raise SystemCallError.new "kill", FFI::errno if r != 0
|
231
|
+
r
|
230
232
|
end
|
231
233
|
|
232
234
|
# Reads sz bytes from task's address space starting at addr.
|
@@ -241,10 +243,10 @@ module Ragweed::Wraposx
|
|
241
243
|
# There is no man page for this function.
|
242
244
|
def vm_read(task, addr, sz=256)
|
243
245
|
buf = FFI::MemoryPointer.new(sz)
|
244
|
-
len = FFI::MemoryPointer(sz
|
246
|
+
len = FFI::MemoryPointer.new(:uint).write_uint(sz)
|
245
247
|
r = Libc.vm_read_overwrite(task, addr, sz, buf, len)
|
246
248
|
raise KernelCallError.new(:vm_read, r) if r != 0
|
247
|
-
|
249
|
+
buf.read_string(len.read_uint)
|
248
250
|
end
|
249
251
|
|
250
252
|
# Writes val to task's memory space at address addr.
|
@@ -258,10 +260,10 @@ module Ragweed::Wraposx
|
|
258
260
|
#
|
259
261
|
# There is no man page for this function.
|
260
262
|
def vm_write(task, addr, val)
|
261
|
-
val = FFI::MemoryPointer.new
|
263
|
+
val = FFI::MemoryPointer.new(val)
|
262
264
|
r = Libc.vm_write(task, addr, val, val.size)
|
263
265
|
raise KernelCallError.new(:vm_write, r) if r != 0
|
264
|
-
|
266
|
+
r
|
265
267
|
end
|
266
268
|
|
267
269
|
# Changes the protection state beginning at addr for size bytes to the mask prot.
|
@@ -279,7 +281,7 @@ module Ragweed::Wraposx
|
|
279
281
|
setmax = setmax ? 1 : 0
|
280
282
|
r = Libc.vm_protect(task, addr, size, setmax, prot)
|
281
283
|
raise KernelCallError.new(:vm_protect, r) if r != 0
|
282
|
-
|
284
|
+
r
|
283
285
|
end
|
284
286
|
|
285
287
|
# Allocates a page in the memory space of the target task.
|
@@ -311,6 +313,7 @@ module Ragweed::Wraposx
|
|
311
313
|
addr.write_int(address)
|
312
314
|
r = Libc.vm_deallocate(task, addr, size)
|
313
315
|
raise KernelCallError.new(r) if r != 0
|
316
|
+
r
|
314
317
|
end
|
315
318
|
|
316
319
|
# Resumes a suspended thread by id.
|
@@ -322,6 +325,7 @@ module Ragweed::Wraposx
|
|
322
325
|
def thread_resume(thread)
|
323
326
|
r = Libc.thread_resume(thread)
|
324
327
|
raise KernelCallError.new(:thread_resume, r) if r != 0
|
328
|
+
r
|
325
329
|
end
|
326
330
|
|
327
331
|
# Suspends a thread by id.
|
@@ -333,6 +337,7 @@ module Ragweed::Wraposx
|
|
333
337
|
def thread_suspend(thread)
|
334
338
|
r = Libc.thread_suspend(thread)
|
335
339
|
raise KernelCallError.new(:thread_suspend, r) if r != 0
|
340
|
+
r
|
336
341
|
end
|
337
342
|
|
338
343
|
# Changes execution to file in path with *args as though called from command line.
|
@@ -8,7 +8,8 @@ class Ragweed::Process
|
|
8
8
|
## Read/write ranges of data or fixnums to/from the process by address.
|
9
9
|
def read(off, sz=4096)
|
10
10
|
a = []
|
11
|
-
|
11
|
+
max = off+sz
|
12
|
+
while off < max
|
12
13
|
a.push(Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, off, 0))
|
13
14
|
return a.pack('L*') if a.last == -1 and FFI.errno != 0
|
14
15
|
off+=4
|
data/ragweed.gemspec
CHANGED
@@ -5,11 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ragweed}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
|
+
s.platform = %q{java}
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
12
|
s.authors = ["tduehr", "struct", "tqbf"]
|
12
|
-
s.date = %q{2011-
|
13
|
+
s.date = %q{2011-06-09}
|
13
14
|
s.description = %q{General debugging tool written in Ruby for OSX/Win32/Linux}
|
14
15
|
s.email = %q{td@matasano.com}
|
15
16
|
s.extra_rdoc_files = [
|
@@ -59,7 +60,6 @@ Gem::Specification.new do |s|
|
|
59
60
|
"lib/ragweed/wraposx/structs.rb",
|
60
61
|
"lib/ragweed/wraposx/thread_context.rb",
|
61
62
|
"lib/ragweed/wraposx/thread_info.rb",
|
62
|
-
"lib/ragweed/wraposx/thread_info.rb.old",
|
63
63
|
"lib/ragweed/wraposx/wraposx.rb",
|
64
64
|
"lib/ragweed/wraptux.rb",
|
65
65
|
"lib/ragweed/wraptux/constants.rb",
|
@@ -74,29 +74,16 @@ Gem::Specification.new do |s|
|
|
74
74
|
s.homepage = %q{http://github.com/tduehr/ragweed}
|
75
75
|
s.rdoc_options = ["--inline-source", "--line-numbers", "--main", "README.rdoc"]
|
76
76
|
s.require_paths = ["lib"]
|
77
|
-
s.rubygems_version = %q{1.5.
|
77
|
+
s.rubygems_version = %q{1.5.1}
|
78
78
|
s.summary = %q{Scriptable debugger}
|
79
|
-
s.test_files = [
|
80
|
-
"examples/hittracertux.rb",
|
81
|
-
"examples/hittracerx.rb",
|
82
|
-
"examples/hook_notepad.rb",
|
83
|
-
"examples/snicker.rb",
|
84
|
-
"examples/tux-example.rb",
|
85
|
-
"spec/ragweed_spec.rb",
|
86
|
-
"spec/spec_helper.rb",
|
87
|
-
"test/test_ragweed.rb"
|
88
|
-
]
|
89
79
|
|
90
80
|
if s.respond_to? :specification_version then
|
91
81
|
s.specification_version = 3
|
92
82
|
|
93
83
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
94
|
-
s.add_runtime_dependency(%q<ffi>, ["~> 1.0"])
|
95
84
|
else
|
96
|
-
s.add_dependency(%q<ffi>, ["~> 1.0"])
|
97
85
|
end
|
98
86
|
else
|
99
|
-
s.add_dependency(%q<ffi>, ["~> 1.0"])
|
100
87
|
end
|
101
88
|
end
|
102
89
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ragweed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.3
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- tduehr
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2011-
|
15
|
+
date: 2011-06-09 00:00:00 -05:00
|
16
16
|
default_executable:
|
17
17
|
dependencies: []
|
18
18
|
|
@@ -68,7 +68,6 @@ files:
|
|
68
68
|
- lib/ragweed/wraposx/structs.rb
|
69
69
|
- lib/ragweed/wraposx/thread_context.rb
|
70
70
|
- lib/ragweed/wraposx/thread_info.rb
|
71
|
-
- lib/ragweed/wraposx/thread_info.rb.old
|
72
71
|
- lib/ragweed/wraposx/wraposx.rb
|
73
72
|
- lib/ragweed/wraptux.rb
|
74
73
|
- lib/ragweed/wraptux/constants.rb
|
@@ -110,12 +109,5 @@ rubygems_version: 1.5.1
|
|
110
109
|
signing_key:
|
111
110
|
specification_version: 3
|
112
111
|
summary: Scriptable debugger
|
113
|
-
test_files:
|
114
|
-
|
115
|
-
- examples/hittracerx.rb
|
116
|
-
- examples/hook_notepad.rb
|
117
|
-
- examples/snicker.rb
|
118
|
-
- examples/tux-example.rb
|
119
|
-
- spec/ragweed_spec.rb
|
120
|
-
- spec/spec_helper.rb
|
121
|
-
- test/test_ragweed.rb
|
112
|
+
test_files: []
|
113
|
+
|
@@ -1,121 +0,0 @@
|
|
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
|