metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,135 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/main'
8
+ require 'metasm/ia32'
9
+
10
+ module Metasm
11
+
12
+ # The x86_64, 64-bit extension of the x86 CPU (x64, em64t, amd64...)
13
+ class X86_64 < Ia32
14
+ # FpReg, SegReg, Farptr unchanged
15
+ # XXX ST(15) ?
16
+
17
+ # Simd extended to 16 regs, xmm only (mmx gone with 80387)
18
+ class SimdReg < Ia32::SimdReg
19
+ double_map 64 => (0..15).map { |n| "mm#{n}" },
20
+ 128 => (0..15).map { |n| "xmm#{n}" }
21
+ end
22
+
23
+ # general purpose registers, all sizes
24
+ # 8 new gprs (r8..r15), set bit R in the REX prefix to reference them (or X/B if in ModRM)
25
+ # aonethusaontehsanothe with 8bit subreg: with no rex prefix, refers to ah ch dh bh (as usual)
26
+ # but whenever the prefix is present, those become unavailable and encodie spl..dil (low byte of rsp/rdi)
27
+ class Reg < Ia32::Reg
28
+ double_map 8 => %w{ al cl dl bl spl bpl sil dil r8b r9b r10b r11b r12b r13b r14b r15b ah ch dh bh},
29
+ 16 => %w{ ax cx dx bx sp bp si di r8w r9w r10w r11w r12w r13w r14w r15w},
30
+ 32 => %w{eax ecx edx ebx esp ebp esi edi r8d r9d r10d r11d r12d r13d r14d r15d eip},
31
+ 64 => %w{rax rcx rdx rbx rsp rbp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15 rip}
32
+
33
+ Sym = @i_to_s[64].map { |s| s.to_sym }
34
+
35
+ # returns a symbolic representation of the register:
36
+ # cx => :rcx & 0xffff
37
+ # ah => (:rax >> 8) & 0xff
38
+ # XXX in x64, 32bits operations are zero-extended to 64bits (eg mov rax, 0x1234_ffff_ffff ; add eax, 1 => rax == 0
39
+ def symbolic(di=nil)
40
+ s = Sym[@val]
41
+ s = di.next_addr if s == :rip and di
42
+ if @sz == 8 and to_s[-1] == ?h
43
+ Expression[[Sym[@val-16], :>>, 8], :&, 0xff]
44
+ elsif @sz == 8
45
+ Expression[s, :&, 0xff]
46
+ elsif @sz == 16
47
+ Expression[s, :&, 0xffff]
48
+ elsif @sz == 32
49
+ Expression[s, :&, 0xffffffff]
50
+ else
51
+ s
52
+ end
53
+ end
54
+
55
+ # checks if two registers have bits in common
56
+ def share?(other)
57
+ raise 'TODO'
58
+ # XXX TODO wtf does formula this do ?
59
+ other.val % (other.sz >> 1) == @val % (@sz >> 1) and (other.sz != @sz or @sz != 8 or other.val == @val)
60
+ end
61
+
62
+ # returns the part of @val to encode in an instruction field
63
+ def val_enc
64
+ if @sz == 8 and @val >= 16; @val-12 # ah, bh, ch, dh
65
+ elsif @val >= 16 # rip
66
+ else @val & 7 # others
67
+ end
68
+ end
69
+
70
+ # returns the part of @val to encode in an instruction's rex prefix
71
+ def val_rex
72
+ if @sz == 8 and @val >= 16 # ah, bh, ch, dh: rex forbidden
73
+ elsif @val >= 16 # rip
74
+ else @val >> 3 # others
75
+ end
76
+ end
77
+ end
78
+
79
+ # ModRM represents indirections (eg dword ptr [eax+4*ebx+12h])
80
+ # 16bit mode unavailable in x64
81
+ # opcodes use 64bit addressing by default, use adsz override (67h) prefix to switch to 32
82
+ # immediate values are encoded as :i32 sign-extended to 64bits
83
+ class ModRM < Ia32::ModRM
84
+ # mod 0/1/2 m 4 => sib
85
+ # mod 0 m 5 => rip+imm
86
+ # sib: i 4 => no index, b 5 => no base
87
+ end
88
+
89
+ class DbgReg < Ia32::DbgReg
90
+ simple_map((0..15).map { |i| [i, "dr#{i}"] })
91
+ end
92
+
93
+ class CtrlReg < Ia32::CtrlReg
94
+ simple_map((0..15).map { |i| [i, "cr#{i}"] })
95
+ end
96
+
97
+ # Create a new instance of an X86 cpu
98
+ # arguments (any order)
99
+ # - instruction set (386, 486, sse2...) [latest]
100
+ # - endianness [:little]
101
+ def initialize(*a)
102
+ super(:latest)
103
+ @size = 64
104
+ a.delete @size
105
+ @endianness = (a & [:big, :little]).first || :little
106
+ a.delete @endianness
107
+ @family = a.pop || :latest
108
+ raise "Invalid arguments #{a.inspect}" if not a.empty?
109
+ raise "Invalid X86_64 family #{@family.inspect}" if not respond_to?("init_#@family")
110
+ end
111
+
112
+ # defines some preprocessor macros to say who we are:
113
+ # TODO
114
+ def tune_prepro(pp)
115
+ super(pp, :itsmeX64) # ask Ia32's to just call super()
116
+ pp.define_weak('_M_AMD64')
117
+ pp.define_weak('_M_X64')
118
+ pp.define_weak('__amd64__')
119
+ pp.define_weak('__x86_64__')
120
+ end
121
+
122
+ def str_to_reg(str)
123
+ # X86_64::Reg != Ia32::Reg
124
+ Reg.from_str(str) if Reg.s_to_i.has_key? str
125
+ end
126
+
127
+ def shortname
128
+ "x64#{'_be' if @endianness == :big}"
129
+ end
130
+ end
131
+
132
+ X64 = X86_64
133
+ AMD64 = X86_64
134
+
135
+ end
@@ -0,0 +1,118 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/x86_64/main'
8
+ require 'metasm/ia32/opcodes'
9
+
10
+ module Metasm
11
+ class X86_64
12
+ def init_cpu_constants
13
+ super()
14
+ @valid_args.concat [:i32, :u32, :i64, :u64] - @valid_args
15
+ end
16
+
17
+ def init_386_common_only
18
+ super()
19
+ # :imm64 => accept a real int64 as :i argument
20
+ # :auto64 => ignore rex_w, always 64-bit op
21
+ # :op32no64 => if write to a 32-bit reg, dont zero the top 32-bits of dest
22
+ @valid_props |= [:imm64, :auto64, :op32no64]
23
+ @opcode_list.delete_if { |o| o.bin[0].to_i & 0xf0 == 0x40 } # now REX prefix
24
+ @opcode_list.each { |o|
25
+ o.props[:imm64] = true if o.bin == [0xB8] # mov reg, <true imm64>
26
+ o.props[:auto64] = true if o.name =~ /^(j|loop|(call|enter|leave|lgdt|lidt|lldt|ltr|pop|push|ret)$)/
27
+ #o.props[:op32no64] = true if o.name =~ // # TODO are there any instr here ?
28
+ }
29
+ addop 'movsxd', [0x63], :mrm
30
+ end
31
+
32
+ # all x86_64 cpu understand <= sse2 instrs
33
+ def init_x8664_only
34
+ init_386_common_only
35
+ init_386_only
36
+ init_387_only # 387 indeed
37
+ init_486_only
38
+ init_pentium_only
39
+ init_p6_only
40
+ init_sse_only
41
+ init_sse2_only
42
+
43
+ @opcode_list.delete_if { |o|
44
+ o.args.include?(:seg2) or
45
+ o.args.include?(:seg2A) or
46
+ %w[aaa aad aam aas bound daa das
47
+ lds les loadall arpl pusha pushad popa popad].include?(o.name)
48
+ }
49
+
50
+ addop 'swapgs', [0x0F, 0x01, 0xF8]
51
+ end
52
+
53
+ def init_sse3
54
+ init_x8664_only
55
+ init_sse3_only
56
+ end
57
+
58
+ def init_vmx
59
+ init_sse3
60
+ init_vmx_only
61
+ end
62
+
63
+ def init_all
64
+ init_vmx
65
+ init_sse42_only
66
+ init_3dnow_only
67
+ end
68
+
69
+ alias init_latest init_all
70
+
71
+
72
+ def addop_macrostr(name, bin, type)
73
+ super(name, bin, type)
74
+ bin = bin.dup
75
+ bin[0] |= 1
76
+ addop(name+'q', bin) { |o| o.props[:opsz] = 64 ; o.props[type] = true }
77
+ end
78
+
79
+ def addop_post(op)
80
+ if op.fields[:d] or op.fields[:w] or op.fields[:s] or op.args.first == :regfp0
81
+ return super(op)
82
+ end
83
+
84
+ dupe = lambda { |o|
85
+ dop = Opcode.new o.name.dup, o.bin.dup
86
+ dop.fields, dop.props, dop.args = o.fields.dup, o.props.dup, o.args.dup
87
+ dop
88
+ }
89
+
90
+ @opcode_list << op
91
+
92
+ if op.args == [:i] or op.args == [:farptr] or op.name[0, 3] == 'ret'
93
+ # define opsz-override version for ambiguous opcodes
94
+ op16 = dupe[op]
95
+ op16.name << '.i16'
96
+ op16.props[:opsz] = 16
97
+ @opcode_list << op16
98
+ # push call ret jz can't 32bit
99
+ op64 = dupe[op]
100
+ op64.name << '.i64'
101
+ op64.props[:opsz] = 64
102
+ @opcode_list << op64
103
+ elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
104
+ op.args.include? :modrm or op.args.include? :modrmA or op.name =~ /loop|xlat/
105
+ # define adsz-override version for ambiguous opcodes (movsq)
106
+ # XXX loop pfx 67 = rip+ecx, 66/rex ignored
107
+ op32 = dupe[op]
108
+ op32.name << '.a32'
109
+ op32.props[:adsz] = 32
110
+ @opcode_list << op32
111
+ op64 = dupe[op]
112
+ op64.name << '.a64'
113
+ op64.props[:adsz] = 64
114
+ @opcode_list << op64
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,68 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/x86_64/opcodes'
8
+ require 'metasm/x86_64/encode'
9
+ require 'metasm/parse'
10
+
11
+ module Metasm
12
+ class X86_64
13
+ def parse_parser_instruction(lexer, instr)
14
+ case instr.raw.downcase
15
+ when '.mode', '.bits'
16
+ if tok = lexer.readtok and tok.type == :string and tok.raw == '64'
17
+ lexer.skip_space
18
+ raise instr, 'syntax error' if ntok = lexer.nexttok and ntok.type != :eol
19
+ else
20
+ raise instr, 'invalid cpu mode, 64bit only'
21
+ end
22
+ else super(lexer, instr)
23
+ end
24
+ end
25
+
26
+ def parse_prefix(i, pfx)
27
+ super(i, pfx) or (i.prefix[:sz] = 64 if pfx == 'code64')
28
+ end
29
+
30
+ # needed due to how ruby inheritance works wrt constants
31
+ def parse_argregclasslist
32
+ [Reg, SimdReg, SegReg, DbgReg, CtrlReg, FpReg]
33
+ end
34
+ # same inheritance sh*t
35
+ def parse_modrm(lex, tok, cpu)
36
+ ModRM.parse(lex, tok, cpu)
37
+ end
38
+
39
+ def parse_instruction_checkproto(i)
40
+ # check ah vs rex prefix
41
+ return if i.args.find { |a| a.kind_of? Reg and a.sz == 8 and a.val >= 16 and
42
+ op = opcode_list.find { |op_| op_.name == i.opname } and
43
+ ((not op.props[:auto64] and i.args.find { |aa| aa.respond_to? :sz and aa.sz == 64 }) or
44
+ i.args.find { |aa| aa.kind_of? Reg and aa.val >= 8 and aa.val < 16 } or # XXX mov ah, cr12...
45
+ i.args.grep(ModRM).find { |aa| (aa.b and aa.b.val >= 8 and aa.b.val < 16) or (aa.i and aa.i.val >= 8 and aa.i.val < 16) })
46
+ }
47
+ super(i)
48
+ end
49
+
50
+ # check if the argument matches the opcode's argument spec
51
+ def parse_arg_valid?(o, spec, arg)
52
+ return if arg.kind_of? ModRM and ((arg.b and arg.b.val == 16 and arg.i) or (arg.i and arg.i.val == 16 and (arg.b or arg.s != 1)))
53
+ return if arg.kind_of? Reg and arg.sz >= 32 and arg.val == 16 # eip/rip only in modrm
54
+ return if o.props[:auto64] and arg.respond_to? :sz and arg.sz == 32
55
+ if o.name == 'movsxd'
56
+ return if not arg.kind_of? Reg and not arg.kind_of? ModRM
57
+ arg.sz ||= 32
58
+ if spec == :reg
59
+ return if not arg.kind_of? Reg
60
+ return arg.sz >= 32
61
+ else
62
+ return arg.sz == 32
63
+ end
64
+ end
65
+ super(o, spec, arg)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,61 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ # A script to help finding performance bottlenecks:
7
+ #
8
+ # $ ruby-prof myscript.rb
9
+ # => String#+ gets called 50k times and takes 30s
10
+ #
11
+ # $ LOGCALLER='String#+' ruby -r bottleneck myscript.rb
12
+ # => String#+ called 40k times from:
13
+ # stuff.rb:42 in Myclass#uglymethod from
14
+ # stuff.rb:32 in Myclass#initialize
15
+ #
16
+ # now you know what to rewrite
17
+
18
+
19
+
20
+ def log_caller(cls, meth, singleton=false, histlen=nil)
21
+ histlen ||= ENV.fetch('LOGCALLER_MAXHIST', 16).to_i
22
+ dec_meth = 'm_' + meth.to_s.gsub(/[^\w]/) { |c| c.unpack('H*')[0] }
23
+ malias = dec_meth + '_log_caller'
24
+ mcntr = '$' + dec_meth + '_counter'
25
+ eval <<EOS
26
+
27
+ #{cls.kind_of?(Class) ? 'class' : 'module'} #{cls}
28
+ #{'class << self' if singleton}
29
+ alias #{malias} #{meth}
30
+
31
+ def #{meth}(*a, &b)
32
+ #{mcntr}[caller[0, #{histlen}]] += 1
33
+ #{malias}(*a, &b)
34
+ end
35
+
36
+ #{'end' if singleton}
37
+ end
38
+
39
+ #{mcntr} = Hash.new(0)
40
+
41
+ at_exit {
42
+ total = #{mcntr}.inject(0) { |a, (k, v)| a+v }
43
+ puts "\#{total} callers of #{cls} #{meth}:"
44
+ #{mcntr}.sort_by { |k, v|
45
+ -v
46
+ }[0, 4].each { |k, v|
47
+ puts " \#{'%.2f%%' % (100.0*v/total)} - \#{v} times from", k, ''
48
+ }
49
+ }
50
+
51
+ EOS
52
+
53
+ end
54
+
55
+ ENV['LOGCALLER'].to_s.split(';').map { |lc|
56
+ next if not lc =~ /^(.*)([.#])(.*)$/
57
+ cls, sg, meth = $1, $2, $3.to_sym
58
+ sg = { '.' => true, '#' => false }[sg]
59
+ cls = cls.split('::').inject(::Object) { |o, cst| o.const_get(cst) }
60
+ log_caller(cls, meth, sg)
61
+ }
@@ -0,0 +1,58 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ #
7
+ # shows the preprocessor path to find a specific line
8
+ # usage: ruby chdr-find.rb 'regex pattern' list of files.h
9
+ #
10
+
11
+ def gets
12
+ l = $ungets
13
+ $ungets = nil
14
+ l || super()
15
+ end
16
+
17
+ def parse(root=false)
18
+ want = false
19
+ ret = []
20
+ while l = gets
21
+ case l = l.strip
22
+ when /^#if/
23
+ ret << l
24
+ r = parse(true)
25
+ if r.empty?
26
+ ret.pop
27
+ else
28
+ want = true
29
+ rr = r.pop
30
+ ret.concat r.map { |l_| (l_[0,3] == '#el' ? ' ' : ' ') << l_ }
31
+ ret << rr
32
+ end
33
+ when /^#el/
34
+ if not root
35
+ $ungets = l
36
+ break
37
+ end
38
+ ret << l
39
+ r = parse
40
+ want = true if not r.empty?
41
+ ret.concat r
42
+ when /^#endif/
43
+ if not root
44
+ $ungets = l
45
+ break
46
+ end
47
+ ret << l
48
+ break
49
+ when /#$srch/ #, /^#include/
50
+ want = true
51
+ ret << l
52
+ end
53
+ end
54
+ want ? ret : []
55
+ end
56
+
57
+ $srch = ARGV.shift
58
+ puts parse
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ # This file is part of Metasm, the Ruby assembly manipulation suite
3
+ # Copyright (C) 2006-2009 Yoann GUILLOT
4
+ #
5
+ # Licence is LGPL, see LICENCE in the top-level directory
6
+
7
+
8
+
9
+ synclen = 6
10
+ ctxlen = 16
11
+
12
+ file1 = ('x'*ctxlen) + File.read(ARGV.shift)
13
+ file2 = ('x'*ctxlen) + File.read(ARGV.shift)
14
+
15
+ count1 = count2 = ctxlen
16
+
17
+ # prints the string in 80 cols
18
+ # with the first column filled with +pfx+
19
+ def show(pfx, str)
20
+ loop do
21
+ if str.length > 79
22
+ len = 79 - str[0...79][/\S+$/].to_s.length
23
+ len = 79 if len == 0
24
+ puts pfx + str[0...len]
25
+ str = str[len..-1]
26
+ else
27
+ puts pfx + str
28
+ break
29
+ end
30
+ end
31
+ end
32
+
33
+ loop do
34
+ w1 = file1[count1]
35
+ w2 = file2[count2]
36
+ break if not w1 and not w2
37
+ if w1 == w2
38
+ count1 += 1
39
+ count2 += 1
40
+ else
41
+ diff1 = diff2 = nil
42
+ catch(:resynced) {
43
+ 1000.times { |depth|
44
+ (-depth..depth).map { |d|
45
+ if d == 0
46
+ [depth, depth]
47
+ elsif d < 0
48
+ [depth, depth+d]
49
+ elsif d > 0
50
+ [depth-d, depth]
51
+ end
52
+ }.each { |dc1, dc2|
53
+ next if !(0...synclen).all? { |i| file1[count1 + dc1 + i] == file2[count2 + dc2 + i] }
54
+
55
+ puts "@#{(count1-ctxlen).to_s 16} #{(count2-ctxlen).to_s 16}"
56
+ show ' ', file1[count1-ctxlen, ctxlen].inspect
57
+ if dc1 > 0
58
+ show '-', file1[count1, dc1].inspect
59
+ end
60
+ if dc2 > 0
61
+ show '+', file2[count2, dc2].inspect
62
+ end
63
+ count1 += dc1
64
+ count2 += dc2
65
+ show ' ', file1[count1, ctxlen].inspect
66
+ puts
67
+
68
+ throw :resynced
69
+ }
70
+ }
71
+ raise 'nomatch..'
72
+ }
73
+ end
74
+ end