iZsh-ragweed 0.1.8
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/History.txt +29 -0
- data/README.rdoc +35 -0
- data/README.txt +9 -0
- data/Rakefile +30 -0
- data/examples/hittracertux.rb +49 -0
- data/examples/hittracerx.rb +63 -0
- data/examples/hook_notepad.rb +9 -0
- data/examples/snicker.rb +183 -0
- data/examples/tux-example.rb +23 -0
- data/lib/ragweed.rb +84 -0
- data/lib/ragweed/arena.rb +55 -0
- data/lib/ragweed/blocks.rb +128 -0
- data/lib/ragweed/debugger32.rb +338 -0
- data/lib/ragweed/debuggerosx.rb +419 -0
- data/lib/ragweed/debuggertux.rb +345 -0
- data/lib/ragweed/detour.rb +223 -0
- data/lib/ragweed/ptr.rb +48 -0
- data/lib/ragweed/rasm.rb +53 -0
- data/lib/ragweed/rasm/isa.rb +1046 -0
- data/lib/ragweed/rasm/util.rb +26 -0
- data/lib/ragweed/sbuf.rb +197 -0
- data/lib/ragweed/trampoline.rb +103 -0
- data/lib/ragweed/utils.rb +88 -0
- data/lib/ragweed/wrap32.rb +53 -0
- data/lib/ragweed/wrap32/debugging.rb +163 -0
- data/lib/ragweed/wrap32/device.rb +49 -0
- data/lib/ragweed/wrap32/event.rb +50 -0
- data/lib/ragweed/wrap32/hooks.rb +23 -0
- data/lib/ragweed/wrap32/overlapped.rb +46 -0
- data/lib/ragweed/wrap32/process.rb +506 -0
- data/lib/ragweed/wrap32/process_token.rb +59 -0
- data/lib/ragweed/wrap32/thread_context.rb +208 -0
- data/lib/ragweed/wrap32/winx.rb +16 -0
- data/lib/ragweed/wrap32/wrap32.rb +526 -0
- data/lib/ragweed/wraposx.rb +53 -0
- data/lib/ragweed/wraposx/constants.rb +112 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +250 -0
- data/lib/ragweed/wraposx/thread_context.rb +203 -0
- data/lib/ragweed/wraposx/thread_info.rb +225 -0
- data/lib/ragweed/wraposx/wraposx.rb +376 -0
- data/lib/ragweed/wraptux.rb +53 -0
- data/lib/ragweed/wraptux/constants.rb +68 -0
- data/lib/ragweed/wraptux/threads.rb +7 -0
- data/lib/ragweed/wraptux/wraptux.rb +76 -0
- data/spec/ragweed_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test_ragweed.rb +0 -0
- metadata +127 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# Dir[File.expand_path("#{File.dirname(__FILE__)}/wraposx/*.rb")].each do |file|
|
2
|
+
# require file
|
3
|
+
# end
|
4
|
+
module Ragweed; end
|
5
|
+
module Ragweed::Wraposx
|
6
|
+
|
7
|
+
# :stopdoc:
|
8
|
+
VERSION = '0.1.6'
|
9
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
10
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
11
|
+
# :startdoc:
|
12
|
+
|
13
|
+
# Returns the version string for the library.
|
14
|
+
#
|
15
|
+
def self.version
|
16
|
+
VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the library path for the module. If any arguments are given,
|
20
|
+
# they will be joined to the end of the libray path using
|
21
|
+
# <tt>File.join</tt>.
|
22
|
+
#
|
23
|
+
def self.libpath( *args )
|
24
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the lpath for the module. If any arguments are given,
|
28
|
+
# they will be joined to the end of the path using
|
29
|
+
# <tt>File.join</tt>.
|
30
|
+
#
|
31
|
+
def self.path( *args )
|
32
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Utility method used to require all files ending in .rb that lie in the
|
36
|
+
# directory below this file that has the same name as the filename passed
|
37
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
38
|
+
# the _filename_ does not have to be equivalent to the directory.
|
39
|
+
#
|
40
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
41
|
+
dir ||= ::File.basename(fname, '.*')
|
42
|
+
search_me = ::File.expand_path(
|
43
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
44
|
+
|
45
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
46
|
+
# require File.dirname(File.basename(__FILE__)) + "/#{x}"
|
47
|
+
|
48
|
+
end
|
49
|
+
end # module Ragweed::Wraposx
|
50
|
+
|
51
|
+
Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
|
52
|
+
|
53
|
+
# EOF
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Ragweed; end
|
2
|
+
module Ragweed::Wraposx;end
|
3
|
+
module Ragweed::Wraposx::Ptrace
|
4
|
+
TRACE_ME = 0 # child declares it's being traced
|
5
|
+
#(READ|WRITE)_[IDU] are not valid in OSX but defined in ptrace.h
|
6
|
+
READ_I = 1 # read word in child's I space
|
7
|
+
READ_D = 2 # read word in child's D space
|
8
|
+
READ_U = 3 # read word in child's user structure
|
9
|
+
WRITE_I = 4 # write word in child's I space
|
10
|
+
WRITE_D = 5 # write word in child's D space
|
11
|
+
WRITE_U = 6 # write word in child's user structure
|
12
|
+
CONTINUE = 7 # continue the child
|
13
|
+
KILL = 8 # kill the child process
|
14
|
+
STEP = 9 # single step the child
|
15
|
+
ATTACH = 10 # trace some running process
|
16
|
+
DETACH = 11 # stop tracing a process
|
17
|
+
SIGEXC = 12 # signals as exceptions for current_proc
|
18
|
+
THUPDATE = 13 # signal for thread
|
19
|
+
ATTACHEXC = 14 # attach to running process with signal exception
|
20
|
+
FORCEQUOTA = 30 # Enforce quota for root
|
21
|
+
DENY_ATTACH = 31 #Prevent process from being traced
|
22
|
+
FIRSTMACH = 32 # for machine-specific requests
|
23
|
+
end
|
24
|
+
|
25
|
+
module Ragweed::Wraposx::Signal
|
26
|
+
#the Ruby module Signal also has this information
|
27
|
+
SIGHUP = 1 # hangup
|
28
|
+
SIGINT = 2 # interrupt
|
29
|
+
SIGQUIT = 3 # quit
|
30
|
+
SIGILL = 4 # illegal instruction (not reset when caught)
|
31
|
+
SIGTRAP = 5 # trace trap (not reset when caught)
|
32
|
+
SIGABRT = 6 # abort()
|
33
|
+
#if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
|
34
|
+
SIGPOLL = 7 # pollable event ([XSR] generated, not supported)
|
35
|
+
#else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
36
|
+
SIGIOT = SIGABRT # compatibility
|
37
|
+
SIGEMT = 7 # EMT instruction
|
38
|
+
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
39
|
+
SIGFPE = 8 # floating point exception
|
40
|
+
SIGKILL = 9 # kill (cannot be caught or ignored)
|
41
|
+
SIGBUS = 10 # bus error
|
42
|
+
SIGSEGV = 11 # segmentation violation
|
43
|
+
SIGSYS = 12 # bad argument to system call
|
44
|
+
SIGPIPE = 13 # write on a pipe with no one to read it
|
45
|
+
SIGALRM = 14 # alarm clock
|
46
|
+
SIGTERM = 15 # software termination signal from kill
|
47
|
+
SIGURG = 16 # urgent condition on IO channel
|
48
|
+
SIGSTOP = 17 # sendable stop signal not from tty
|
49
|
+
SIGTSTP = 18 # stop signal from tty
|
50
|
+
SIGCONT = 19 # continue a stopped process
|
51
|
+
SIGCHLD = 20 # to parent on child stop or exit
|
52
|
+
SIGTTIN = 21 # to readers pgrp upon background tty read
|
53
|
+
SIGTTOU = 22 # like TTIN for output if (tp->t_local<OSTOP)
|
54
|
+
#if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
|
55
|
+
SIGIO = 23 # input/output possible signal
|
56
|
+
#endif
|
57
|
+
SIGXCPU = 24 # exceeded CPU time limit
|
58
|
+
SIGXFSZ = 25 # exceeded file size limit
|
59
|
+
SIGVTALRM = 26 # virtual time alarm
|
60
|
+
SIGPROF = 27 # profiling time alarm
|
61
|
+
#if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
|
62
|
+
SIGWINCH = 28 # window size changes
|
63
|
+
SIGINFO = 29 # information request
|
64
|
+
#endif
|
65
|
+
SIGUSR1 = 30 # user defined signal 1
|
66
|
+
SIGUSR2 = 31 # user defined signal 2
|
67
|
+
end
|
68
|
+
|
69
|
+
module Ragweed::Wraposx::Wait
|
70
|
+
NOHANG = 0x01 # [XSI] no hang in wait/no child to reap
|
71
|
+
UNTRACED = 0x02 # [XSI] notify on stop, untraced child
|
72
|
+
EXITED = 0x04 # [XSI] Processes which have exitted
|
73
|
+
STOPPED = 0x08 # [XSI] Any child stopped by signal
|
74
|
+
CONTINUED = 0x10 # [XSI] Any child stopped then continued
|
75
|
+
NOWWAIT = 0x20 # [XSI] Leave process returned waitable
|
76
|
+
end
|
77
|
+
|
78
|
+
module Ragweed::Wraposx::Vm; end
|
79
|
+
module Ragweed::Wraposx::Vm::Prot
|
80
|
+
#vm_protect permission flags for memory spaces
|
81
|
+
READ = 0x1 #read permission
|
82
|
+
WRITE = 0x2 #write permission
|
83
|
+
EXECUTE = 0x4 #execute permission
|
84
|
+
NONE = 0x0 #no rights
|
85
|
+
ALL = 0x7 #all permissions
|
86
|
+
end
|
87
|
+
|
88
|
+
module Ragweed::Wraposx::Vm::Sm
|
89
|
+
# share_mode
|
90
|
+
SM_COW = 0x1
|
91
|
+
SM_PRIVATE = 0x2
|
92
|
+
SM_EMPTY = 0x3
|
93
|
+
SM_SHARED = 0x4
|
94
|
+
SM_TRUESHARED = 0x5
|
95
|
+
SM_PRIVATE_ALIASED = 0x6
|
96
|
+
SM_SHARED_ALIASED = 0x7
|
97
|
+
end
|
98
|
+
|
99
|
+
module Ragweed::Wraposx::Dl
|
100
|
+
RTLD_LAZY = 0x1
|
101
|
+
RTLD_NOW = 0x2
|
102
|
+
RTLD_LOCAL = 0x4
|
103
|
+
RTLD_GLOBAL = 0x8
|
104
|
+
RTLD_NOLOAD = 0x10
|
105
|
+
RTLD_NODELETE = 0x80
|
106
|
+
RTLD_FIRST = 0x100 #/* Mac OS X 10.5 and later */
|
107
|
+
|
108
|
+
# Special handle arguments for dlsym().
|
109
|
+
#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
|
110
|
+
#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
|
111
|
+
#define RTLD_SELF ((void *) -3) /* Search this and subsequent objects (Mac OS X 10.5 and later) */
|
112
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# Exception objects for kernel errors likely in Wraposx
|
2
|
+
# If this were a C extension I'd use #ifdef on each to only create the required ones.
|
3
|
+
|
4
|
+
module Ragweed; end
|
5
|
+
module Ragweed::Wraposx; end
|
6
|
+
module Ragweed::Wraposx::KernelReturn
|
7
|
+
SUCCESS = { :value => 0, :message => 'Not an error'}
|
8
|
+
INVALID_ADDRESS = { :value => 1, :message => 'Specified address is not currently valid.'}
|
9
|
+
PROTECTION_FAILURE = { :value => 2, :message => 'Specified memory is valid, but does not permit the required forms of access.'}
|
10
|
+
NO_SPACE = { :value => 3, :message => 'The address range specified is already in use, or no address range of the size specified could be found.'}
|
11
|
+
INVALID_ARGUMENT = { :value => 4, :message => 'The function requested was not applicable to this type of argument, or an argument is invalid'}
|
12
|
+
FAILURE = { :value => 5, :message => 'The function could not be performed. A catch-all.'}
|
13
|
+
RESOURCE_SHORTAGE = { :value => 6, :message => 'A system resource could not be allocated to fulfill this request. This failure may not be permanent.'}
|
14
|
+
NOT_RECEIVER = { :value => 7, :message => 'The task in question does not hold receive rights for the port argument.'}
|
15
|
+
NO_ACCESS = { :value => 8, :message => 'Bogus access restriction.'}
|
16
|
+
MEMORY_FAILURE = { :value => 9, :message => 'During a page fault, the target address refers to a memory object that has been destroyed. This failure is permanent.'}
|
17
|
+
MEMORY_ERROR = { :value => 10, :message => 'During a page fault, the memory object indicated that the data could not be returned. This failure may be temporary; future attempts to access this same data may succeed, as defined by the memory object.'}
|
18
|
+
ALREADY_IN_SET = { :value => 11, :message => 'The receive right is already a member of the portset.'}
|
19
|
+
NOT_IN_SET = { :value => 12, :message => 'The receive right is not a member of a port set.'}
|
20
|
+
NAME_EXISTS = { :value => 13, :message => 'The name already denotes a right in the task.'}
|
21
|
+
ABORTED = { :value => 14, :message => 'The operation was aborted. Ipc code will catch this and reflect it as a message error.'}
|
22
|
+
INVALID_NAME = { :value => 15, :message => 'The name doesn\'t denote a right in the task.'}
|
23
|
+
INVALID_TASK = { :value => 16, :message => 'Target task isn\'t an active task.'}
|
24
|
+
INVALID_RIGHT = { :value => 17, :message => 'The name denotes a right, but not an appropriate right.'}
|
25
|
+
INVALID_VALUE = { :value => 18, :message => 'A blatant range error.'}
|
26
|
+
UREFS_OVERFLOW = { :value => 19, :message => 'Operation would overflow limit on user-references.'}
|
27
|
+
INVALID_CAPABILITY = { :value => 20, :message => 'The supplied (port) capability is improper.'}
|
28
|
+
RIGHT_EXISTS = { :value => 21, :message => 'The task already has send or receive rights for the port under another name.'}
|
29
|
+
INVALID_HOST = { :value => 22, :message => 'Target host isn\'t actually a host.'}
|
30
|
+
MEMORY_PRESENT = { :value => 23, :message => 'An attempt was made to supply "precious" data for memory that is already present in a memory object.'}
|
31
|
+
MEMORY_DATA_MOVED = { :value => 24, :message => 'A page was requested of a memory manager via memory_object_data_request for an object using a MEMORY_OBJECT_COPY_CALL strategy, with the VM_PROT_WANTS_COPY flag being used to specify that the page desired is for a copy of the object, and the memory manager has detected the page was pushed into a copy of the object while the kernel was walking the shadow chain from the copy to the object. This error code is delivered via memory_object_data_error and is handled by the kernel (it forces the kernel to restart the fault). It will not be seen by users.'}
|
32
|
+
MEMORY_RESTART_COPY = { :value => 25, :message => 'A strategic copy was attempted of an object upon which a quicker copy is now possible. The caller should retry the copy using vm_object_copy_quickly. This error code is seen only by the kernel.'}
|
33
|
+
INVALID_PROCESSOR_SET = { :value => 26, :message => 'An argument applied to assert processor set privilege was not a processor set control port.'}
|
34
|
+
POLICY_LIMIT = { :value => 27, :message => 'The specified scheduling attributes exceed the thread\'s limits.'}
|
35
|
+
INVALID_POLICY = { :value => 28, :message => 'The specified scheduling policy is not currently enabled for the processor set.'}
|
36
|
+
INVALID_OBJECT = { :value => 29, :message => 'The external memory manager failed to initialize the memory object.'}
|
37
|
+
ALREADY_WAITING = { :value => 30, :message => 'A thread is attempting to wait for an event for which there is already a waiting thread.'}
|
38
|
+
DEFAULT_SET = { :value => 31, :message => 'An attempt was made to destroy the default processor set.'}
|
39
|
+
EXCEPTION_PROTECTED = { :value => 32, :message => 'An attempt was made to fetch an exception port that is protected, or to abort a thread while processing a protected exception.'}
|
40
|
+
INVALID_LEDGER = { :value => 33, :message => 'A ledger was required but not supplied.'}
|
41
|
+
INVALID_MEMORY_CONTROL= { :value => 34, :message => 'The port was not a memory cache control port.'}
|
42
|
+
INVALID_SECURITY = { :value => 35, :message => 'An argument supplied to assert security privilege was not a host security port.'}
|
43
|
+
NOT_DEPRESSED = { :value => 36, :message => 'thread_depress_abort was called on a thread which was not currently depressed.'}
|
44
|
+
TERMINATED = { :value => 37, :message => 'Object has been terminated and is no longer available'}
|
45
|
+
LOCK_SET_DESTROYED = { :value => 38, :message => 'Lock set has been destroyed and is no longer available.'}
|
46
|
+
LOCK_UNSTABLE = { :value => 39, :message => 'The thread holding the lock terminated before releasing the lock'}
|
47
|
+
LOCK_OWNED = { :value => 40, :message => 'The lock is already owned by another thread'}
|
48
|
+
LOCK_OWNED_SELF = { :value => 41, :message => 'The lock is already owned by the calling thread'}
|
49
|
+
SEMAPHORE_DESTROYED = { :value => 42, :message => 'Semaphore has been destroyed and is no longer available.'}
|
50
|
+
RPC_SERVER_TERMINATED = { :value => 43, :message => 'Return from RPC indicating the target server was terminated before it successfully replied '}
|
51
|
+
RPC_TERMINATE_ORPHAN = { :value => 44, :message => 'Terminate an orphaned activation.'}
|
52
|
+
RPC_CONTINUE_ORPHAN = { :value => 45, :message => 'Allow an orphaned activation to continue executing.'}
|
53
|
+
NOT_SUPPORTED = { :value => 46, :message => 'Empty thread activation (No thread linked to it)'}
|
54
|
+
NODE_DOWN = { :value => 47, :message => 'Remote node down or inaccessible.'}
|
55
|
+
NOT_WAITING = { :value => 48, :message => 'A signalled thread was not actually waiting.'}
|
56
|
+
OPERATION_TIMED_OUT = { :value => 49, :message => 'Some thread-oriented operation (semaphore_wait) timed out'}
|
57
|
+
RETURN_MAX = { :value => 0x100, :message => 'Maximum return value allowable'}
|
58
|
+
|
59
|
+
module_function
|
60
|
+
# Much like Signals.list returns a hash of the possible kernel call return values.
|
61
|
+
def list
|
62
|
+
constants.inject({}){|a, c| a.merge! c => const_get(c)}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Ragweed::Wraposx::KErrno; end
|
67
|
+
|
68
|
+
# Exception class for mach kernel calls. Works mostly like SystemCallError.
|
69
|
+
# Subclasses are individual error conditions and case equality (===) is done by class then error number (KErrno)
|
70
|
+
class Ragweed::Wraposx::KernelCallError < StandardError
|
71
|
+
DEFAULT_MESSAGE = "Unknown Error"
|
72
|
+
attr_reader :kerrno
|
73
|
+
|
74
|
+
# Returns a subclass of KernelCallError based on the KernelReturn value err
|
75
|
+
def self.new(msg = "", err = nil)
|
76
|
+
if msg.kind_of? Fixnum
|
77
|
+
err = msg
|
78
|
+
msg = ""
|
79
|
+
end
|
80
|
+
mesg = ""
|
81
|
+
|
82
|
+
klass = Ragweed::Wraposx::KErrno.constants.detect{|x| Ragweed::Wraposx::KErrno.const_get(x).const_get("KErrno") == err}
|
83
|
+
if (klass.nil? or klass.empty?)
|
84
|
+
o = self.allocate
|
85
|
+
o.instance_variable_set("@kerrno", err)
|
86
|
+
mesg = "Unknown kernel error"
|
87
|
+
else
|
88
|
+
o = Ragweed::Wraposx::KErrno.const_get(klass).allocate
|
89
|
+
mesg = Ragweed::Wraposx::KernelReturn.const_get(klass)[:message]
|
90
|
+
end
|
91
|
+
|
92
|
+
if o.class.const_defined?("KErrno")
|
93
|
+
o.instance_variable_set("@kerrno", o.class.const_get("KErrno"))
|
94
|
+
else
|
95
|
+
o.instance_variable_set("@kerrno", err)
|
96
|
+
mesg = "#{mesg}: #{err}" if err
|
97
|
+
end
|
98
|
+
|
99
|
+
mesg = "#{mesg} - #{msg}" if !(msg.nil? or msg.to_s.empty?)
|
100
|
+
o.send(:initialize, mesg)
|
101
|
+
return o
|
102
|
+
end
|
103
|
+
|
104
|
+
# Case equality. Returns true if self and other are KernelCallError or when error numbers match.
|
105
|
+
def self.===(other)
|
106
|
+
return false if not other.kind_of?(Ragweed::Wraposx::KernelCallError)
|
107
|
+
return true if self == Ragweed::Wraposx::KernelCallError
|
108
|
+
|
109
|
+
begin
|
110
|
+
return self.const_get("KErrno") == other.const_get("KErrno")
|
111
|
+
rescue
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialize(msg)
|
117
|
+
super msg
|
118
|
+
end
|
119
|
+
|
120
|
+
# This block builds the subclasses for KernelCallError
|
121
|
+
Ragweed::Wraposx::KernelReturn.list.each do |k, v|
|
122
|
+
case k.intern
|
123
|
+
when :SUCCESS
|
124
|
+
when :RETURN_MAX
|
125
|
+
else
|
126
|
+
klass = Ragweed::Wraposx::KErrno.const_set(k, Class.new(Ragweed::Wraposx::KernelCallError){
|
127
|
+
def self.new(msg = "")
|
128
|
+
o = self.allocate
|
129
|
+
o.instance_variable_set "@kerrno", self.const_get("KErrno")
|
130
|
+
mesg = ""
|
131
|
+
klass = self.name.split("::").last
|
132
|
+
if Ragweed::Wraposx::KernelReturn.const_defined?(klass)
|
133
|
+
mesg = Ragweed::Wraposx::KernelReturn.const_get(klass)[:message]
|
134
|
+
else
|
135
|
+
mesg = "Unknown kernel error"
|
136
|
+
end
|
137
|
+
mesg = "#{mesg} - #{msg}" if not (msg.nil? or msg.empty?)
|
138
|
+
o.send(:initialize, mesg)
|
139
|
+
puts self
|
140
|
+
return o
|
141
|
+
end
|
142
|
+
})
|
143
|
+
klass.const_set "KErrno", v[:value]
|
144
|
+
klass.const_set "DEFAULT_MESSAGE", v[:message]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
module Ragweed; end
|
2
|
+
module Ragweed::Wraposx; end
|
3
|
+
module Ragweed::Wraposx::Vm
|
4
|
+
# these are flavor arguments for vm_region
|
5
|
+
# more to be added as support for 64bit processes gets added
|
6
|
+
REGION_BASIC_INFO = 10
|
7
|
+
REGION_EXTENDED_INFO = 11
|
8
|
+
REGION_TOP_INFO = 12
|
9
|
+
|
10
|
+
# behavior identifiers
|
11
|
+
BEHAVIOR_DEFAULT = 0 # /* default */
|
12
|
+
BEHAVIOR_RANDOM = 1 # /* random */
|
13
|
+
BEHAVIOR_SEQUENTIAL = 2 # /* forward sequential */
|
14
|
+
BEHAVIOR_RSEQNTL = 3 # /* reverse sequential */
|
15
|
+
BEHAVIOR_WILLNEED = 4 # /* will need in near future */
|
16
|
+
BEHAVIOR_DONTNEED = 5 # /* dont need in near future */
|
17
|
+
|
18
|
+
#Virtual memory map inheritance values for vm_inherit_t
|
19
|
+
INHERIT_SHARE = 0 # /* share with child */
|
20
|
+
INHERIT_COPY = 1 # /* copy into child */
|
21
|
+
INHERIT_NONE = 2 # /* absent from child */
|
22
|
+
INHERIT_DONATE_COPY = 3 # /* copy and delete */
|
23
|
+
INHERIT_DEFAULT = 1 # VM_INHERIT_COPY
|
24
|
+
INHERIT_LAST_VALID = 2 # VM_INHERIT_NONE
|
25
|
+
|
26
|
+
#define VM_REGION_BASIC_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_basic_info_data_t)/sizeof(int)))
|
27
|
+
#define VM_REGION_EXTENDED_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_extended_info_data_t)/sizeof(int)))
|
28
|
+
#define VM_REGION_TOP_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_top_info_data_t)/sizeof(int)))
|
29
|
+
FLAVORS = { REGION_BASIC_INFO => {:size => 30, :count => 8},
|
30
|
+
REGION_EXTENDED_INFO => {:size => 32, :count => 8},
|
31
|
+
REGION_TOP_INFO => {:size => 17,:count => 5}
|
32
|
+
}
|
33
|
+
|
34
|
+
module Pflags
|
35
|
+
READ = 0x1 #read permission
|
36
|
+
WRITE = 0x2 #write permission
|
37
|
+
EXECUTE = 0x4 #execute permission
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Memory region info base class.
|
42
|
+
# Currently Apple only supports the basic flavor. The other two flavors
|
43
|
+
# are included for completeness.
|
44
|
+
#
|
45
|
+
class Ragweed::Wraposx::RegionInfo
|
46
|
+
def initialize(str=nil)
|
47
|
+
refresh(str) if str
|
48
|
+
end
|
49
|
+
|
50
|
+
# (re)loads the data from str
|
51
|
+
def refresh(str)
|
52
|
+
fields = self.class.const_get :FIELDS
|
53
|
+
if str and not str.empty?
|
54
|
+
str.unpack(fields.map {|x| x[1]}.join("")).each_with_index do |val, i|
|
55
|
+
raise "i is nil" if i.nil?
|
56
|
+
instance_variable_set "@#{ fields[i][0] }".intern, val
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
fields = self.class.const_get :FIELDS
|
63
|
+
fields.map {|f| send(f[0])}.pack(fields.map {|x| x[1]}.join(""))
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.get(t, a, flavor)
|
67
|
+
self.new(Ragweed::Wraposx::vm_region_raw(t, a, flavor))
|
68
|
+
end
|
69
|
+
|
70
|
+
def get(t, a)
|
71
|
+
refresh(Ragweed::Wraposx::vm_region_raw(t, a, self.class.const_get(:FLAVOR)))
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
fields = self.class.const_get(:FIELDS)
|
76
|
+
body = lambda do
|
77
|
+
fields.map do |f|
|
78
|
+
"#{f[0]}=#{send(f[0]).to_s}"
|
79
|
+
end.join(", ")
|
80
|
+
end
|
81
|
+
"#<#{self.class.name.split("::").last} #{body.call}>"
|
82
|
+
end
|
83
|
+
|
84
|
+
def dump(&block)
|
85
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
86
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
87
|
+
|
88
|
+
string =<<EOM
|
89
|
+
-----------------------------------------------------------------------
|
90
|
+
INFO:
|
91
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
92
|
+
max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
|
93
|
+
inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
|
94
|
+
shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
|
95
|
+
reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
|
96
|
+
offset: #{self.offset.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.offset)}
|
97
|
+
behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
|
98
|
+
user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
|
99
|
+
address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
|
100
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
101
|
+
EOM
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Ragweed::Wraposx::RegionBasicInfo < Ragweed::Wraposx::RegionInfo
|
106
|
+
|
107
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO
|
108
|
+
|
109
|
+
(FIELDS = [ [:protection, "i"], # The current protection for the region.
|
110
|
+
[:max_protection, "i"], # The maximum protection allowed for the region.
|
111
|
+
[:inheritance, "I"], # The inheritance attribute for the region.
|
112
|
+
[:shared, "I"], # Shared indicator. If true, the region is shared by another task. If false, the region is not shared.
|
113
|
+
[:reserved, "I"], # If true the region is protected from random allocation.
|
114
|
+
[:offset, "L"], # The region's offset into the memory object. The region begins at this offset.
|
115
|
+
[:behavior, "i"], # Expected reference pattern for the memory.
|
116
|
+
[:user_wired_count, "S"],
|
117
|
+
[:address, "L"], # The returned address
|
118
|
+
[:size, "I"] # size of memory region returned
|
119
|
+
]).each {|x| attr_accessor x[0]}
|
120
|
+
|
121
|
+
def dump(&block)
|
122
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
123
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
124
|
+
|
125
|
+
string =<<EOM
|
126
|
+
-----------------------------------------------------------------------
|
127
|
+
INFO:
|
128
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
129
|
+
max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
|
130
|
+
inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
|
131
|
+
shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
|
132
|
+
reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
|
133
|
+
offset: #{self.offset.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.offset)}
|
134
|
+
behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
|
135
|
+
user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
|
136
|
+
address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
|
137
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
138
|
+
EOM
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.get(t, a)
|
142
|
+
self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Ragweed::Wraposx::RegionExtendedInfo < Ragweed::Wraposx::RegionInfo
|
147
|
+
|
148
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_EXTENDED_INFO
|
149
|
+
(FIELDS = [ [:protection, "i"],
|
150
|
+
[:user_tag, "I"],
|
151
|
+
[:pages_resident, "I"],
|
152
|
+
[:pages_shared_now_private, "I"],
|
153
|
+
[:pages_swapped_out, "I"],
|
154
|
+
[:pages_dirtied, "I"],
|
155
|
+
[:ref_count, "I"],
|
156
|
+
[:shadow_depth, "S"],
|
157
|
+
[:external_pager, "C"],
|
158
|
+
[:share_mode, "C"],
|
159
|
+
[:address, "L"],
|
160
|
+
[:size, "I"] ]).each {|x| attr_accessor x[0]}
|
161
|
+
|
162
|
+
def dump(&block)
|
163
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
164
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
165
|
+
|
166
|
+
string =<<EOM
|
167
|
+
-----------------------------------------------------------------------
|
168
|
+
INFO:
|
169
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
170
|
+
user_tag: #{self.user_tag.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_tag)}
|
171
|
+
pages_resident: #{self.pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_resident)}
|
172
|
+
pages_shared_now_private: #{self.pages_shared_now_private.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_shared_now_private)}
|
173
|
+
pages_swapped_out: #{self.pages_swapped_out.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_swapped_out)}
|
174
|
+
pages_dirtied: #{self.pages_dirtied.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_dirtied)}
|
175
|
+
ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
|
176
|
+
shadow_depth: #{self.shadow_depth.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shadow_depth)}
|
177
|
+
external_pager: #{self.external_pager.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.external_pager)}
|
178
|
+
share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
|
179
|
+
address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
|
180
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
181
|
+
EOM
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.get(t, a)
|
185
|
+
self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class Ragweed::Wraposx::RegionTopInfo < Ragweed::Wraposx::RegionInfo
|
190
|
+
|
191
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_TOP_INFO
|
192
|
+
|
193
|
+
(FIELDS = [ [:obj_id, "I"],
|
194
|
+
[:ref_count, "I"],
|
195
|
+
[:private_pages_resident, "I"],
|
196
|
+
[:shared_pages_resident, "I"],
|
197
|
+
[:share_mode, "C"],
|
198
|
+
[:address, "L"],
|
199
|
+
[:size, "I"]]).each {|x| attr_accessor x[0]}
|
200
|
+
|
201
|
+
def dump(&block)
|
202
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
203
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
204
|
+
|
205
|
+
string =<<EOM
|
206
|
+
-----------------------------------------------------------------------
|
207
|
+
INFO:
|
208
|
+
obj_id: #{self.obj_id.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.obj_id)}
|
209
|
+
ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
|
210
|
+
private_pages_resident: #{self.private_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.private_pages_resident)}
|
211
|
+
shared_pages_resident: #{self.shared_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared_pages_resident)}
|
212
|
+
share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
|
213
|
+
address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
|
214
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
215
|
+
EOM
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.get(t, a)
|
219
|
+
self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
module Ragweed::Wraposx
|
224
|
+
class << self
|
225
|
+
|
226
|
+
# Returns a string containing the memory region information for task
|
227
|
+
# at address.
|
228
|
+
# Currently Apple only supports the basic flavor. The other two flavors
|
229
|
+
# are included for completeness.
|
230
|
+
#
|
231
|
+
# kern_return_t vm_region
|
232
|
+
# (vm_task_t target_task,
|
233
|
+
# vm_address_t address,
|
234
|
+
# vm_size_t size,
|
235
|
+
# vm_region_flavor_t flavor,
|
236
|
+
# vm_region_info_t info,
|
237
|
+
# mach_msg_type_number_t info_count,
|
238
|
+
# memory_object_name_t object_name);
|
239
|
+
def vm_region_raw(task, address, flavor)
|
240
|
+
info = ("\x00"*64).to_ptr
|
241
|
+
count = ([Vm::FLAVORS[flavor][:count]].pack("I_")).to_ptr
|
242
|
+
address = ([address].pack("L_")).to_ptr
|
243
|
+
objn = ([0].pack("I_")).to_ptr
|
244
|
+
sz = ("\x00"*SIZEOFINT).to_ptr
|
245
|
+
r = CALLS["libc!vm_region:IPPIPPP=I"].call(task, address, sz, flavor, info, count, objn).first
|
246
|
+
raise KernelCallError.new(:vm_region, r) if r != 0
|
247
|
+
return "#{info.to_s(Vm::FLAVORS[flavor][:size])}#{address.to_s(SIZEOFLONG)}#{sz.to_s(SIZEOFINT)}"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|