metasm 1.0.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 (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