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 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
- At this time only Ruby 1.8.x has been tested. We are actively investigating both 64 bit
24
- support for each platform and support for Ruby 1.9.x. Unfortunately, both of these things
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 are currently moving to FFI from ruby/dl. This will likely result in some incompatibilities if you are using the low level functions calls directly. It will also add ffi as a dependency. This move is to facilitate 1.9 and 64bit support.
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/2010 Matasano Security, LLC All Rights Reserved
55
+ Copyright 2009-2011 Matasano Security, LLC All Rights Reserved
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.2.3
@@ -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 = (thread or self.threads.first)
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 = (thread or self.threads.first)
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 = (thread or self.threads.first)
363
- Ragweed::Wraposx::ThreadContext.get(thread)
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
- 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)
371
- regs.set(thread)
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
- return Ragweed::Wraposx::RegionBasicInfo.get(@task, addr)
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
- return Ragweed::Wraposx::RegionExtendedInfo.get(@task, addr)
410
+ Ragweed::Wraposx::Vm::RegionExtendedInfo::FLAVOR
410
411
  when :top
411
- return Ragweed::Wraposx::RegionTopInfo.get(@task, addr)
412
+ Ragweed::Wraposx::Vm::RegionTopInfo::FLAVOR
413
+ when Integer
414
+ flavor
412
415
  else
413
416
  warn "Unknown flavor requested. Returning RegionBasicInfo."
414
- return Ragweed::Wraposx::RegionBasicInfo.get(@task, addr)
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
@@ -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 of the search_* methods
233
- def search_page(base, max, val)
234
- loc = Array.new
235
-
236
- while base.to_i < max.to_i
237
- r = Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, base, 0)
238
- if r == val
239
- loc.push(base)
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
- base += 1
253
+ d.close
242
254
  end
243
255
 
244
256
  loc
245
257
  end
246
258
 
247
- ## Search the heap for a value
248
- def search_heap(val)
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 =~ /\[heap\]/
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 = search_page(s, max, val)
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 = Array.new
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.concat(search_page(k, max, val))
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(:uint8, Vm::FLAVORS[flavor][:size])
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::Flavors[flavor][:class].new info
270
- ret.region_size = size.read_ulong
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.eip)}
224
-
225
- RAX: #{self.rax.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.eax)}
226
- RBX: #{self.rbx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.ebx)}
227
- RCX: #{self.rcx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.ecx)}
228
- RDX: #{self.rdx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.edx)}
229
- RDI: #{self.rdi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.edi)}
230
- RSI: #{self.rsi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.esi)}
231
- RBP: #{self.rbp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.ebp)}
232
- RSP: #{self.rsp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.esp)}
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 + case self[:tsh][:flavor]
293
+ ret += case self[:tsh][:flavor]
268
294
  when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
269
- self[:uts].ts32.members.map{|x| [x.to_s, x.to_s + "="]}
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].ts64.members.map{|x| [x.to_s, x.to_s + "="]}
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 + case self[:tsh][:flavor]
307
+ ret += case self[:tsh][:flavor]
282
308
  when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
283
- self[:uts].ts32.members.map{|x| [x, (x.to_s + "=").intern]}
309
+ self[:uts][:ts32].members.map{|x| [x, (x.to_s + "=").intern]}
284
310
  when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
285
- self[:uts].ts64.members.map{|x| [x, (x.to_s + "=").intern]}
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].ts32.__send__(:[]=, mth, *args)
331
+ self[:uts][:ts32].__send__(:[]=, mth, *args)
306
332
  when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
307
- self[:uts].ts64.__send__(:[]=, mth, *args)
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].ts32.__send__(:[], meth, *args)
345
+ self[:uts][:ts32].__send__(:[], meth, *args)
320
346
  when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
321
- self[:uts].ts64.__send__(:[], meth, *args)
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 + case self[:dsh][:flavor]
468
+ ret += case self[:dsh][:flavor]
439
469
  when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
440
- self[:uds].ds32.members.map{|x| [x.to_s, x.to_s + "="]}
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].ds64.members.map{|x| [x.to_s, x.to_s + "="]}
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 + case self[:dsh][:flavor]
482
+ ret += case self[:dsh][:flavor]
453
483
  when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
454
- self[:uds].ds32.members.map{|x| [x, (x.to_s + "=").intern]}
484
+ self[:uds][:ds32].members.map{|x| [x, (x.to_s + "=").intern]}
455
485
  when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
456
- self[:uds].ds64.members.map{|x| [x, (x.to_s + "=").intern]}
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].ds32.__send__(:[]=, mth, *args)
506
+ self[:uds][:ds32].__send__(:[]=, mth, *args)
477
507
  when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
478
- self[:uds].ds64.__send__(:[]=, mth, *args)
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].ds32.__send__(:[], meth, *args)
520
+ self[:uds][:ds32].__send__(:[], meth, *args)
491
521
  when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
492
- self[:uds].ds64.__send__(:[], meth, *args)
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
- #comment
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 + case self[:esh][:flavor]
613
+ ret += case self[:esh][:flavor]
580
614
  when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
581
- self[:ues].es32.members.map{|x| [x.to_s, x.to_s + "="]}
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].es64.members.map{|x| [x.to_s, x.to_s + "="]}
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 + case self[:esh][:flavor]
627
+ ret += case self[:esh][:flavor]
594
628
  when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
595
- self[:ues].es32.members.map{|x| [x, (x.to_s + "=").intern]}
629
+ self[:ues][:es32].members.map{|x| [x, (x.to_s + "=").intern]}
596
630
  when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
597
- self[:ues].es64.members.map{|x| [x, (x.to_s + "=").intern]}
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].es32.__send__(:[]=, mth, *args)
651
+ self[:ues][:es32].__send__(:[]=, mth, *args)
618
652
  when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
619
- self[:ues].es64.__send__(:[]=, mth, *args)
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].es32.__send__(:[], meth, *args)
665
+ self[:ues][:es32].__send__(:[], meth, *args)
632
666
  when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
633
- self[:ues].es64.__send__(:[], meth, *args)
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, :mach_msg_type_number_t], :kern_return_t
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::FLAVOR[flavor][:class], 1
883
- count = FFI::MemoryPointer.new(:int, 1).write_int Ragweed::Wraposx::ThreadContext::FLAVOR[flavor][:count]
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::FLAVOR[flavor][:class].new state
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
- # mach_msg_number_t new_state_count);
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::FLAVOR[flavor][:class].new state
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 :int, 1
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.read_int
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 :int, 1
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.read_array_of_int(count.read_int)
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.to_l32)
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
- return buf.to_str(len.to_str(4).to_l32)
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
- return nil
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
- return nil
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
- while off < off+sz
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.1"
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-04-13}
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.2}
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.1
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-04-13 00:00:00 -05:00
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
- - examples/hittracertux.rb
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