duran 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +11 -0
  3. data/Rakefile +29 -0
  4. data/VERSION +1 -0
  5. data/client_src/dr_include/dr_api.h +102 -0
  6. data/client_src/dr_include/dr_app.h +92 -0
  7. data/client_src/dr_include/dr_config.h +650 -0
  8. data/client_src/dr_include/dr_defines.h +391 -0
  9. data/client_src/dr_include/dr_events.h +1057 -0
  10. data/client_src/dr_include/dr_ir_instr.h +1214 -0
  11. data/client_src/dr_include/dr_ir_instrlist.h +149 -0
  12. data/client_src/dr_include/dr_ir_macros.h +2426 -0
  13. data/client_src/dr_include/dr_ir_opcodes.h +768 -0
  14. data/client_src/dr_include/dr_ir_opnd.h +1170 -0
  15. data/client_src/dr_include/dr_ir_utils.h +708 -0
  16. data/client_src/dr_include/dr_proc.h +327 -0
  17. data/client_src/dr_include/dr_tools.h +1304 -0
  18. data/client_src/duran.c +57 -0
  19. data/client_src/extconf.rb +28 -0
  20. data/lib/duran.rb +18 -0
  21. data/lib/duran/app.rb +8 -0
  22. data/lib/duran/defines.rb +39 -0
  23. data/lib/duran/events.rb +156 -0
  24. data/lib/duran/ir_opcodes.rb +616 -0
  25. data/lib/duran/ir_opnd.rb +329 -0
  26. data/lib/duran/ir_utils.rb +133 -0
  27. data/lib/duran/proc.rb +49 -0
  28. data/lib/duran/structs.rb +20 -0
  29. data/lib/duran/structs/exception.rb +23 -0
  30. data/lib/duran/structs/fault_fragment_info.rb +34 -0
  31. data/lib/duran/structs/instruction.rb +15 -0
  32. data/lib/duran/structs/machine_context.rb +80 -0
  33. data/lib/duran/structs/memory_info.rb +12 -0
  34. data/lib/duran/structs/module_data.rb +61 -0
  35. data/lib/duran/structs/module_names.rb +24 -0
  36. data/lib/duran/structs/operand.rb +15 -0
  37. data/lib/duran/structs/restore_state_info.rb +30 -0
  38. data/lib/duran/structs/signal_info.rb +41 -0
  39. data/lib/duran/structs/tracedump.rb +50 -0
  40. data/lib/duran/tools.rb +214 -0
  41. metadata +104 -0
@@ -0,0 +1,49 @@
1
+
2
+ module Duran
3
+ # XXX feature_bit_t is an enum, but there's gaps and i'm feeling lazy atm
4
+ typedef :uint, :feature_bit_t
5
+
6
+ enum :cache_size_t, [
7
+ :CACHE_SIZE_8_KB, #/**< L1 or L2 cache size of 8 KB. */
8
+ :CACHE_SIZE_16_KB, #/**< L1 or L2 cache size of 16 KB. */
9
+ :CACHE_SIZE_32_KB, #/**< L1 or L2 cache size of 32 KB. */
10
+ :CACHE_SIZE_64_KB, #/**< L1 or L2 cache size of 64 KB. */
11
+ :CACHE_SIZE_128_KB, #/**< L1 or L2 cache size of 128 KB. */
12
+ :CACHE_SIZE_256_KB, #/**< L1 or L2 cache size of 256 KB. */
13
+ :CACHE_SIZE_512_KB, #/**< L1 or L2 cache size of 512 KB. */
14
+ :CACHE_SIZE_1_MB, #/**< L1 or L2 cache size of 1 MB. */
15
+ :CACHE_SIZE_2_MB, #/**< L1 or L2 cache size of 2 MB. */
16
+ :CACHE_SIZE_UNKNOWN #/**< Unknown L1 or L2 cache size. */
17
+ ]
18
+
19
+ enum :vendor_t, [:intel, :amd, :unknown]
20
+
21
+
22
+ attach_function :proc_get_cache_line_size, [], :size_t
23
+ attach_function :proc_is_cache_aligned, [:pointer], :bool
24
+ attach_function :proc_bump_to_end_of_cache_line, [:ptr_uint_t], :ptr_uint_t
25
+ attach_function :proc_get_containing_page, [:pointer], :pointer
26
+ attach_function :proc_get_vendor, [], :vendor_t
27
+ attach_function :proc_get_family, [], :uint
28
+ attach_function :proc_get_type, [], :uint
29
+ attach_function :proc_get_model, [], :uint
30
+ attach_function :proc_get_stepping, [], :uint
31
+ attach_function :proc_get_brand_string, [], :string
32
+ attach_function :proc_get_L1_icache_size, [], :cache_size_t
33
+ attach_function :proc_get_L1_dcache_size, [], :cache_size_t
34
+ attach_function :proc_get_L2_cache_size, [], :cache_size_t
35
+ attach_function :proc_get_cache_size_str, [:cache_size_t], :string
36
+ attach_function :proc_fpstate_save_size, [], :size_t
37
+ attach_function :proc_save_fpstate, [:pointer], :size_t
38
+ attach_function :proc_restore_fpstate, [:pointer], :void
39
+ attach_function :proc_has_feature, [:feature_bit_t], :bool
40
+ attach_function :proc_get_all_feature_bits, [], :pointer
41
+
42
+ attach_function :dr_insert_save_fpstate,
43
+ [:dr_ctx_t, :pointer, :pointer, Operand], :void
44
+
45
+ attach_function :dr_insert_restore_fpstate,
46
+ [:dr_ctx_t, :pointer, :pointer, Operand], :void
47
+
48
+ end
49
+
@@ -0,0 +1,20 @@
1
+
2
+ module Duran
3
+ class DRYStruct < FFI::Struct
4
+ include FFI::DRY::StructHelper
5
+ end
6
+
7
+ end
8
+
9
+ require 'duran/structs/operand'
10
+ require 'duran/structs/instruction'
11
+ require 'duran/structs/machine_context'
12
+ require 'duran/structs/fault_fragment_info'
13
+ require 'duran/structs/restore_state_info'
14
+ require 'duran/structs/exception'
15
+ require 'duran/structs/signal_info'
16
+ require 'duran/structs/memory_info'
17
+ require 'duran/structs/module_names'
18
+ require 'duran/structs/module_data'
19
+ require 'duran/structs/tracedump'
20
+
@@ -0,0 +1,23 @@
1
+
2
+ module Duran
3
+ class Exception < DRYStruct
4
+ dsl_layout do
5
+ struct :mcontext, MachineContext, :desc => "Context at exception point"
6
+
7
+ field :record, :pointer, :desc => "Ptr. to the Win32 EXCEPTION_RECORD"
8
+
9
+ # aligns to 8 bytes to avoid differences in padding... XXX TODO confirm!
10
+
11
+ struct :raw_mcontext, MachineContext, :desc => \
12
+ "The raw pre-translated machine state at the exception interruption "+
13
+ "point inside the code cache. Clients are cautioned when examining "+
14
+ "code cache instructions to not rely on any details of code inserted "+
15
+ "other than their own."
16
+
17
+ struct :fault_fragment_info, FaultFragmentInfo, :desc => \
18
+ "Information about the code fragment inside the code cache at "+
19
+ "the exception interruption point. "
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module Duran
2
+ # See _dr_fault_fragment_info_t in dr_events.h
3
+ #
4
+ # Data structure passed within dr_exception_t, dr_siginfo_t, and
5
+ # dr_restore_state_info_t.
6
+ # Contains information about the code fragment inside the code cache
7
+ # at the exception/signal/translation interruption point.
8
+ class FaultFragmentInfo < DRYStruct
9
+ dsl_layout do
10
+ field :tag, :pointer, :desc => \
11
+ "The tag of the code fragment inside the code cache at the "+
12
+ "exception/signal/translation interruption point. NULL for "+
13
+ "interruption not in the code cache."
14
+
15
+ field :cache_start_pc, :pointer, :desc => \
16
+ "The start address of the code fragment inside the code cache at "+
17
+ "the exception/signal/translation interruption point. NULL for "+
18
+ "interruption not in the code cache. "+
19
+ "Clients are cautioned when examining code cache instructions to not"+
20
+ "rely on any details of code inserted other than their own. "
21
+
22
+ field :is_trace, :bool, :desc => \
23
+ "Indicates whether the interrupted code fragment is a trace"
24
+
25
+ field :app_code_consistent, :bool, :desc => \
26
+ "Indicates whether the original application code containing the "+
27
+ "code corresponding to the exception/signal/translation interruption "+
28
+ "point is guaranteed to still be in the same state it was when the "+
29
+ "code was placed in the code cache. This guarantee varies "+
30
+ "depending on the type of cache consistency being used by DR."
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module Duran
3
+ # Internal structure of instr_t is below abstraction layer, but we
4
+ # provide its size so that it can be used in stack variables
5
+ # instead of always allocated on the heap.
6
+ class Instruction < DRYStruct
7
+ dsl_layout do
8
+ if ::Duran::ARCH == :x64
9
+ array :black_box_uint, [:uint, 26]
10
+ else
11
+ array :black_box_uint, [:uint, 16]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,80 @@
1
+
2
+ module Duran
3
+ class MachineContext < DRYStruct
4
+ NUM_XMM_SLOTS =
5
+ ::Duran::ARCH == :x64 ? ( ::Duran::PLATFORM == :windows ? 6 : 16) : 8
6
+
7
+ # comment from dr_defines.h:
8
+ #
9
+ # The SSE registers xmm0-xmm5 (-xmm15 on Linux) are volatile
10
+ # (caller-saved) for 64-bit and WOW64, and are actually zeroed out on
11
+ # Windows system calls. These fields are ignored for 32-bit processes
12
+ # that are not WOW64, or if the underlying processor does not support
13
+ # SSE. Use dr_mcontext_xmm_fields_valid() to determine whether the
14
+ # fields are valid.
15
+ class XMM_t < FFI::Struct
16
+ # Really a union, but FFI structs and unions with arrays are lots
17
+ # of broken so we fake it with our own helper methods.
18
+ layout :u8_stub, [:uchar, 16]
19
+
20
+ def u8
21
+ self[:u8_stub].to_a
22
+ end
23
+
24
+ def u64
25
+ self[:u8_stub].to_ptr.get_array_of_uint64(0,2)
26
+ end
27
+
28
+ def u32
29
+ self[:u8_stub].to_ptr.get_array_of_uint32(0,4)
30
+ end
31
+
32
+ alias_method :reg, (::Duran::ARCH == :x64 ? :u64 : :u32)
33
+ end
34
+
35
+ dsl_layout do
36
+ field :xdi, :reg_t, :desc => "platform-independent rdi/edi register"
37
+ field :xsi, :reg_t, :desc => "platform-independent rsi/esi register"
38
+ field :xbp, :reg_t, :desc => "platform-independent rbp/ebp register"
39
+ field :xsp, :reg_t, :desc => "platform-independent rsp/esp register"
40
+ field :xbx, :reg_t, :desc => "platform-independent rbx/ebx register"
41
+ field :xdx, :reg_t, :desc => "platform-independent rdx/edx register"
42
+ field :xcx, :reg_t, :desc => "platform-independent rcx/ecx register"
43
+ field :xax, :reg_t, :desc => "platform-independent rax/eax register"
44
+ if ::Duran::ARCH == :x64
45
+ field :r8, :reg_t, :desc => "r8 register"
46
+ field :r9, :reg_t, :desc => "r9 register"
47
+ field :r10, :reg_t, :desc => "r10 register"
48
+ field :r11, :reg_t, :desc => "r11 register"
49
+ field :r12, :reg_t, :desc => "r12 register"
50
+ field :r13, :reg_t, :desc => "r13 register"
51
+ field :r14, :reg_t, :desc => "r14 register"
52
+ field :r15, :reg_t, :desc => "r15 register"
53
+ end
54
+ array :xmm_stub, [:uchar, NUM_XMM_SLOTS*XMM_t.size]
55
+ field :xflags, :reg_t, :desc => 'platform-independent rflags/eflags register'
56
+ field :xip, :pointer, :desc => "platform-independent rip/eip register"
57
+ end
58
+
59
+ alias_method :pc, :xip
60
+ alias_method :pc=, :xip=
61
+
62
+ # Create e/r aliases for all the platform-independent register accessors
63
+ # named based on our architecture.
64
+ reg_pfx = ::Duran::ARCH == :x64 ? "r" : "e"
65
+ [:di, :si, :bp, :sp, :bx, :dx, :cx, :ax, :flags, :ip].each do |reg_sfx|
66
+ alias_method :"#{reg_pfx}#{reg_sfx}", :"x#{reg_sfx}"
67
+ alias_method :"#{reg_pfx}#{reg_sfx}=", :"x#{reg_sfx}="
68
+ end
69
+
70
+ def xmm
71
+ off=0
72
+ Array.new(NUM_XMM_SLOTS) do
73
+ r = XMM_t.new(self[:xmm_stub].to_ptr+off)
74
+ off += XMM_t.size
75
+ r
76
+ end
77
+ end
78
+ end
79
+ end
80
+
@@ -0,0 +1,12 @@
1
+ module Duran
2
+ enum :mem_type, [:free, :image, :data]
3
+
4
+ class MemoryInfo < DRYStruct
5
+ dsl_layout do
6
+ field :base_pc, :pointer, :desc => "Starting address of memory region"
7
+ field :mem_size, :size_t, :desc => "Size of region"
8
+ field :prot, :uint, :desc => "Protection of region (MEMPROT_* flags)"
9
+ field :mem_type, :uint, :desc => "Type of region"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,61 @@
1
+
2
+ module Duran
3
+
4
+ class ModuleData < DRYStruct
5
+
6
+ class VersionNumber < DRYStruct
7
+ dsl_layout do
8
+ field :p2, :ushort
9
+ field :p1, :ushort
10
+ field :p4, :ushort
11
+ field :p3, :ushort
12
+ end
13
+
14
+ def ms
15
+ to_ptr.get_uint32(0)
16
+ end
17
+
18
+ def ls
19
+ to_ptr.get_uint32(4)
20
+ end
21
+
22
+ def version
23
+ to_ptr.get_uint64(0)
24
+ end
25
+ end
26
+
27
+ dsl_layout do
28
+ field :start_addr, :app_pc,
29
+ :desc => 'starting address of this module'
30
+
31
+ field :end_addr, :app_pc,
32
+ :desc => 'ending address of this module'
33
+
34
+ field :entry_point, :app_pc,
35
+ :desc => 'entry point for this module as specified in the headers'
36
+
37
+ field :flags, :uint, :desc => 'Reserved, set to 0'
38
+
39
+ struct :names, ModuleNames,
40
+ :desc => 'struct containing names for this module.'
41
+
42
+ field :full_path, :string,
43
+ :desc => 'full path to the file backing this module'
44
+
45
+ if ::Duran::PLATFORM == :windows
46
+ struct :file_version, VersionNumber,
47
+ :desc => "file version number from .rsrc section"
48
+
49
+ struct :product_version, VersionNumber,
50
+ :desc => "product version number from .rsrc section"
51
+
52
+ field :module_internal_size, :size_t,
53
+ :desc => "module internal size (from PE headers SizeOfImage)"
54
+
55
+ end
56
+ end
57
+
58
+ alias_method :handle, :start_addr
59
+ end
60
+ end
61
+
@@ -0,0 +1,24 @@
1
+
2
+ module Duran
3
+ class ModuleNames < DRYStruct
4
+ dsl_layout do
5
+ field :module_name, :string,
6
+ :desc => "The name of the module from the PE or ELF header."
7
+
8
+ field :file_name, :string,
9
+ :desc => "The file name used to load this module."
10
+
11
+ if PLATFORM == :windows
12
+ field :exe_name, :string,
13
+ :desc => "The executable name used to launch the process."
14
+
15
+ field :rsrc_name, :string,
16
+ :desc => "The internal name given to the module in its resource."
17
+
18
+ else # :linux
19
+ field :inode, :uint64, :desc => "The inode of the module mapped in."
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,15 @@
1
+ module Duran
2
+ # Internal structure of opnd_t is below abstraction layer
3
+ # but FFI needs to know field sizes to copy it around
4
+ class Operand < DRYStruct
5
+ dsl_layout do
6
+ if ::Duran::ARCH == :x64
7
+ field :black_box_uint, :uint
8
+ field :black_box_uint64, :uint64
9
+ else
10
+ array :black_box_uint, [:uint, 3]
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,30 @@
1
+
2
+ module Duran
3
+ # see _dr_restore_state_info_t in dr_events.h
4
+ #
5
+ # Data structure passed to a restore_state_ex event handler (see
6
+ # dr_register_restore_state_ex_event()). Contains the machine
7
+ # context at the translation point and other translation
8
+ # information.
9
+ class RestoreStateInfo < DRYStruct
10
+ dsl_layout do
11
+ struct :mcontext, MachineContext, :desc => \
12
+ "The application machine state at the translation point."
13
+
14
+ field :raw_mcontext_valid, :bool, :desc => \
15
+ "Whether raw_mcontext is valid."
16
+
17
+ struct :raw_mcontext, MachineContext, :desc => \
18
+ "The raw pre-translated machine state at the translation "+
19
+ "interruption point inside the code cache. Clients are "+
20
+ "cautioned when examining code cache instructions to not rely on "+
21
+ "any details of code inserted other than their own."
22
+
23
+ struct :fault_fragment, FaultFragmentInfo, :desc => \
24
+ "Information about the code fragment inside the code cache "+
25
+ "at the translation interruption point."
26
+
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,41 @@
1
+
2
+ module Duran
3
+
4
+ # Data structure passed with a signal event. Contains the machine
5
+ # context at the signal interruption point and other signal
6
+ # information.
7
+ class SignalInfo < DRYStruct
8
+ dsl_layout do
9
+ field :sig, :int, :desc => "The signal number."
10
+
11
+ field :context, :pointer, :desc => \
12
+ "The context of the thread receiving the signal."
13
+
14
+ struct :mcontext, MachineContext, :desc => \
15
+ "The application machine state at the signal interruption point."
16
+
17
+ struct :raw_mcontext, MachineContext, :desc => \
18
+ "The raw pre-translated machine state at the signal interruption "+
19
+ "point inside the code cache. NULL for delayable signals. Clients "+
20
+ "are cautioned when examining code cache instructions to not rely on "+
21
+ "any details of code inserted other than their own."
22
+
23
+ field :raw_mcontext_valid, :bool, :desc => "Whether raw_context is valid"
24
+
25
+ field :access_address, :pointer, :desc => \
26
+ "For SIGBUS and SIGSEGV, the address whose access caused the signal "+
27
+ "to be raised (as calculated by DR)."
28
+
29
+ field :blocked, :bool, :desc => \
30
+ "Indicates this signal is blocked. DR_SIGNAL_BYPASS is not allowed, "+
31
+ "and a second event will be sent if the signal is later delivered to "+
32
+ "the application. Events are only sent for blocked non-delayable "+
33
+ "signals, not for delayable signals."
34
+
35
+ struct :fault_fragment_info, FaultFragmentInfo, :desc => \
36
+ "Information about the code fragment inside the code cache "+
37
+ "at the signal interruption point."
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+
2
+ module Duran
3
+ class TracedumpFileHeader < DRYStruct
4
+ dsl_layout do
5
+ field :version, :int,
6
+ :desc => "The DynamoRIO version that created the file"
7
+
8
+ field :x64, :bool,
9
+ :desc => "Whether a 64-bit DynamoRIO library created the file."
10
+
11
+ field :linkcount_size, :int,
12
+ :desc => "Size of the linkcount (linkcounts are deprecated)"
13
+ end
14
+ end
15
+
16
+ class TraceDumpTraceHeader < DRYStruct
17
+ dsl_layout do
18
+ field :frag_id, :int, :desc => "Identifier for the trace"
19
+ field :tag, :app_pc, :desc => "Application address for start of trace"
20
+ field :cache_start, :app_pc, :desc => "Code cache start address."
21
+ field :entry_offs, :int, :desc => "Offset into trace of normal entry."
22
+ field :num_exits, :int, :desc => "Number of exits from the trace."
23
+ field :code_size, :int, :desc => "Length of the trace in the code cache"
24
+ field :num_bbs, :uint, :desc => "Number of bbs making up the trace"
25
+ field :x64, :bool, :desc => "Whether the trace contains 64-bit code"
26
+ end
27
+ end
28
+
29
+ class TraceDumpStubData < DRYStruct
30
+ class Count < FFI::Union
31
+ layout :count32, :uint32, :count64, :uint64
32
+
33
+ def count32; self[:count32]; end
34
+ def count32=(val); self[:count32]=val; end
35
+ def count64; self[:count64]; end
36
+ def count64=(val); self[:count64]=val; end
37
+ end
38
+
39
+ dsl_layout do
40
+ field :cti_offs, :int, :desc => "Offset from the start of the fragment"
41
+ field :stub_pc, :app_pc, :desc => "Code cache address of the stub"
42
+ field :target, :app_pc, :desc => "Target of the stub"
43
+ field :linked, :bool, :desc => "Whether the stub is linked to its target"
44
+ field :stub_size, :int, :desc => "Length of stub_code array"
45
+ struct :count, Count , :desc => "32 or 64 bit execution count"
46
+ field :stub_code, :byte, :desc => "variable sized"
47
+ end
48
+ end
49
+ end
50
+