ragweed 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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.2
@@ -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.
data/ragweed.gemspec CHANGED
@@ -5,11 +5,11 @@
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.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["tduehr", "struct", "tqbf"]
12
- s.date = %q{2011-04-13}
12
+ s.date = %q{2011-06-08}
13
13
  s.description = %q{General debugging tool written in Ruby for OSX/Win32/Linux}
14
14
  s.email = %q{td@matasano.com}
15
15
  s.extra_rdoc_files = [
@@ -59,7 +59,6 @@ Gem::Specification.new do |s|
59
59
  "lib/ragweed/wraposx/structs.rb",
60
60
  "lib/ragweed/wraposx/thread_context.rb",
61
61
  "lib/ragweed/wraposx/thread_info.rb",
62
- "lib/ragweed/wraposx/thread_info.rb.old",
63
62
  "lib/ragweed/wraposx/wraposx.rb",
64
63
  "lib/ragweed/wraptux.rb",
65
64
  "lib/ragweed/wraptux/constants.rb",
@@ -76,16 +75,6 @@ Gem::Specification.new do |s|
76
75
  s.require_paths = ["lib"]
77
76
  s.rubygems_version = %q{1.5.2}
78
77
  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
78
 
90
79
  if s.respond_to? :specification_version then
91
80
  s.specification_version = 3
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ragweed
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 2
10
+ version: 0.2.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - tduehr
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-04-13 00:00:00 -05:00
20
+ date: 2011-06-08 00:00:00 -05:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -87,7 +87,6 @@ files:
87
87
  - lib/ragweed/wraposx/structs.rb
88
88
  - lib/ragweed/wraposx/thread_context.rb
89
89
  - lib/ragweed/wraposx/thread_info.rb
90
- - lib/ragweed/wraposx/thread_info.rb.old
91
90
  - lib/ragweed/wraposx/wraposx.rb
92
91
  - lib/ragweed/wraptux.rb
93
92
  - lib/ragweed/wraptux/constants.rb
@@ -135,12 +134,5 @@ rubygems_version: 1.5.2
135
134
  signing_key:
136
135
  specification_version: 3
137
136
  summary: Scriptable debugger
138
- test_files:
139
- - examples/hittracertux.rb
140
- - examples/hittracerx.rb
141
- - examples/hook_notepad.rb
142
- - examples/snicker.rb
143
- - examples/tux-example.rb
144
- - spec/ragweed_spec.rb
145
- - spec/spec_helper.rb
146
- - test/test_ragweed.rb
137
+ test_files: []
138
+
@@ -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