duran 0.1.0

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.
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
+