metasm 1.0.1 → 1.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
|
@@ -9,7 +9,7 @@ class AsmOpcodeWidget < DrawableWidget
|
|
|
9
9
|
attr_accessor :dasm
|
|
10
10
|
# nr of raw data bytes to display next to decoded instructions
|
|
11
11
|
attr_accessor :raw_data_length
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def initialize_widget(dasm, parent_widget)
|
|
14
14
|
@dasm = dasm
|
|
15
15
|
@parent_widget = parent_widget
|
|
@@ -22,9 +22,7 @@ class AsmOpcodeWidget < DrawableWidget
|
|
|
22
22
|
@view_max = @dasm.sections.map { |s, e| s + e.length }.max rescue nil
|
|
23
23
|
@view_addr = @dasm.prog_binding['entrypoint'] || @view_min || 0
|
|
24
24
|
|
|
25
|
-
@default_color_association =
|
|
26
|
-
:instruction => :black, :address => :blue, :caret => :black, :raw_data => :black,
|
|
27
|
-
:background => :white, :cursorline_bg => :paleyellow, :hl_word => :palered }
|
|
25
|
+
@default_color_association = ColorTheme.merge :raw_data => :black
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
def resized(w, h)
|
|
@@ -124,19 +122,7 @@ class AsmOpcodeWidget < DrawableWidget
|
|
|
124
122
|
# must not include newline
|
|
125
123
|
render = lambda { |str, color|
|
|
126
124
|
fullstr << str
|
|
127
|
-
|
|
128
|
-
stmp = str
|
|
129
|
-
pre_x = 0
|
|
130
|
-
while stmp =~ /^(.*?)(\b#{Regexp.escape @hl_word}\b)/
|
|
131
|
-
s1, s2 = $1, $2
|
|
132
|
-
pre_x += s1.length * @font_width
|
|
133
|
-
hl_x = s2.length * @font_width
|
|
134
|
-
draw_rectangle_color(:hl_word, x+pre_x, y, hl_x, @font_height)
|
|
135
|
-
pre_x += hl_x
|
|
136
|
-
stmp = stmp[s1.length+s2.length..-1]
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
draw_string_color(color, x, y, str)
|
|
125
|
+
draw_string_hl(color, x, y, str)
|
|
140
126
|
x += str.length * @font_width
|
|
141
127
|
}
|
|
142
128
|
|
|
@@ -154,7 +140,7 @@ class AsmOpcodeWidget < DrawableWidget
|
|
|
154
140
|
|
|
155
141
|
# draw text until screen is full
|
|
156
142
|
while y < height
|
|
157
|
-
if
|
|
143
|
+
if invb[curaddr]
|
|
158
144
|
nl[]
|
|
159
145
|
@dasm.label_alias[curaddr].to_a.each { |name|
|
|
160
146
|
render["#{name}:", :label]
|
|
@@ -251,7 +237,7 @@ class AsmOpcodeWidget < DrawableWidget
|
|
|
251
237
|
# redraws the caret, change the hilighted word, redraw if needed
|
|
252
238
|
def update_caret
|
|
253
239
|
if update_hl_word(@line_text[@caret_y], @caret_x) or @caret_y != @oldcaret_y
|
|
254
|
-
redraw
|
|
240
|
+
redraw
|
|
255
241
|
elsif @oldcaret_x != @caret_x
|
|
256
242
|
invalidate_caret(@oldcaret_x, @oldcaret_y)
|
|
257
243
|
invalidate_caret(@caret_x, @caret_y)
|
|
@@ -30,7 +30,7 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
30
30
|
oldcb = @code.bg_color_callback
|
|
31
31
|
@code.bg_color_callback = lambda { |a|
|
|
32
32
|
if a == @dbg.pc
|
|
33
|
-
|
|
33
|
+
:red_bg
|
|
34
34
|
# TODO breakpoints & stuff
|
|
35
35
|
elsif oldcb; oldcb[a]
|
|
36
36
|
end
|
|
@@ -48,8 +48,8 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
48
48
|
|
|
49
49
|
pc = @dbg.resolve_expr(@watchpoint[@code])
|
|
50
50
|
graph = :graph if @dbg.disassembler.function_blocks(pc).to_a.length < 100
|
|
51
|
-
@code.focus_addr(pc, graph)
|
|
52
|
-
@mem.focus_addr(0, :hex)
|
|
51
|
+
@code.focus_addr(pc, graph, true)
|
|
52
|
+
@mem.focus_addr(0, :hex, true)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def swapin_tid
|
|
@@ -98,10 +98,16 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
98
98
|
|
|
99
99
|
# TODO check_target always, incl when :stopped
|
|
100
100
|
def post_dbg_run
|
|
101
|
+
# focus currently stopped threads
|
|
102
|
+
if @dbg.state == :running and tt = @dbg.tid_stuff.find { |tid, tstuff| tstuff[:state] != :running }
|
|
103
|
+
@dbg.tid = tt[0]
|
|
104
|
+
end
|
|
105
|
+
|
|
101
106
|
want_redraw = true
|
|
102
107
|
return if @idle_checking ||= nil # load only one bg proc
|
|
103
108
|
@idle_checking = true
|
|
104
109
|
Gui.idle_add {
|
|
110
|
+
protect {
|
|
105
111
|
@dbg.check_target
|
|
106
112
|
if @dbg.state == :running
|
|
107
113
|
redraw if want_redraw # redraw once if the target is running (less flicker with singlestep)
|
|
@@ -121,6 +127,7 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
121
127
|
}
|
|
122
128
|
redraw
|
|
123
129
|
false
|
|
130
|
+
}
|
|
124
131
|
}
|
|
125
132
|
end
|
|
126
133
|
|
|
@@ -166,7 +173,10 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
166
173
|
l = listwindow('running processes', list,
|
|
167
174
|
:noshow => true,
|
|
168
175
|
:color_callback => lambda { |le| [:grey, :palegrey] if le[0] == me }
|
|
169
|
-
) { |e|
|
|
176
|
+
) { |e|
|
|
177
|
+
i.text = e[0]
|
|
178
|
+
i.keypress(:enter) if l.destroyed?
|
|
179
|
+
}
|
|
170
180
|
l.x += l.width
|
|
171
181
|
l.show
|
|
172
182
|
false
|
|
@@ -198,10 +208,28 @@ class DbgWidget < ContainerVBoxWidget
|
|
|
198
208
|
case f
|
|
199
209
|
when /\.(c|h|cpp)$/; @dbg.disassembler.parse_c_file(f)
|
|
200
210
|
when /\.map$/; @dbg.load_map(f)
|
|
201
|
-
when /\.rb$/; @dbg.load_plugin(f)
|
|
211
|
+
when /\.rb$/; @dbg.load_plugin(f) ; @console.add_log "loaded plugin #{File.basename(f, '.rb')}"
|
|
202
212
|
else messagebox("unsupported file extension #{f}")
|
|
203
213
|
end
|
|
204
214
|
end
|
|
215
|
+
|
|
216
|
+
def extend_contextmenu(tg, menu, addr=nil)
|
|
217
|
+
if addr
|
|
218
|
+
bm = tg.new_menu
|
|
219
|
+
bl = @dbg.all_breakpoints(addr)
|
|
220
|
+
if not bl.empty?
|
|
221
|
+
tg.addsubmenu(bm, '_clear breakpoint') { bl.each { |b| @dbg.del_bp(b) } }
|
|
222
|
+
end
|
|
223
|
+
tg.addsubmenu(bm, '_go here') { @dbg.bpx(addr, true) ; dbg_continue }
|
|
224
|
+
tg.addsubmenu(bm, '_bpx') { @dbg.bpx(addr) }
|
|
225
|
+
tg.addsubmenu(bm, 'bpm _read') { @dbg.hwbp(addr, :r, 1) }
|
|
226
|
+
tg.addsubmenu(bm, 'bpm _write') { @dbg.hwbp(addr, :w, 1) }
|
|
227
|
+
tg.addsubmenu(menu, '_bp', bm)
|
|
228
|
+
end
|
|
229
|
+
if @parent_widget.respond_to?(:extend_contextmenu)
|
|
230
|
+
@parent_widget.extend_contextmenu(tg, menu, addr)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
205
233
|
end
|
|
206
234
|
|
|
207
235
|
|
|
@@ -221,10 +249,9 @@ class DbgRegWidget < DrawableWidget
|
|
|
221
249
|
swapin_tid
|
|
222
250
|
|
|
223
251
|
@reg_pos = [] # list of x y w h vx of the reg drawing on widget, vx is x of value
|
|
224
|
-
|
|
225
|
-
@default_color_association =
|
|
226
|
-
|
|
227
|
-
:inactive => :palegrey }
|
|
252
|
+
|
|
253
|
+
@default_color_association = ColorTheme.merge :label => :text, :data => :blue, :write_pending => :darkred,
|
|
254
|
+
:changed => :green, :caret => :text, :inactive => :palegrey
|
|
228
255
|
end
|
|
229
256
|
|
|
230
257
|
def swapin_tid
|
|
@@ -262,7 +289,6 @@ class DbgRegWidget < DrawableWidget
|
|
|
262
289
|
end
|
|
263
290
|
|
|
264
291
|
def paint
|
|
265
|
-
curaddr = 0
|
|
266
292
|
x = 1
|
|
267
293
|
y = 0
|
|
268
294
|
|
|
@@ -402,7 +428,7 @@ class DbgRegWidget < DrawableWidget
|
|
|
402
428
|
@write_pending[reg] = v
|
|
403
429
|
rsz = 1
|
|
404
430
|
end
|
|
405
|
-
|
|
431
|
+
|
|
406
432
|
if rsz == 1
|
|
407
433
|
@caret_reg += 1
|
|
408
434
|
@caret_reg = @registers.length if @caret_reg >= @registers.length + @flags.length
|
|
@@ -472,8 +498,8 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
472
498
|
|
|
473
499
|
@dbg.set_log_proc { |l| add_log l }
|
|
474
500
|
|
|
475
|
-
@default_color_association =
|
|
476
|
-
:background => :black, :status => :black, :status_bg => '088'
|
|
501
|
+
@default_color_association = ColorTheme.merge :log => :palegrey, :curline => :white, :caret => :yellow,
|
|
502
|
+
:background => :black, :status => :black, :status_bg => '088'
|
|
477
503
|
|
|
478
504
|
init_commands
|
|
479
505
|
end
|
|
@@ -513,6 +539,21 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
513
539
|
clipboard_copy(txt)
|
|
514
540
|
end
|
|
515
541
|
|
|
542
|
+
# copy/paste word under cursor (paste when on last line)
|
|
543
|
+
def rightclick(x, y)
|
|
544
|
+
y -= height % @font_height
|
|
545
|
+
y = y.to_i / @font_height
|
|
546
|
+
hc = height / @font_height
|
|
547
|
+
x /= @font_width
|
|
548
|
+
if y >= hc - 2
|
|
549
|
+
keypress_ctrl ?v
|
|
550
|
+
else
|
|
551
|
+
txt = @log.reverse[@log_offset + hc - y - 3].to_s
|
|
552
|
+
word = txt[0...x].to_s[/\w*$/] << txt[x..-1].to_s[/^\w*/]
|
|
553
|
+
clipboard_copy(word)
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
516
557
|
def mouse_wheel(dir, x, y)
|
|
517
558
|
case dir
|
|
518
559
|
when :up; @log_offset += 3
|
|
@@ -531,12 +572,12 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
531
572
|
|
|
532
573
|
w_w = width
|
|
533
574
|
|
|
534
|
-
|
|
575
|
+
y -= @font_height
|
|
535
576
|
draw_rectangle_color(:status_bg, 0, y, w_w, @font_height)
|
|
536
577
|
str = "#{@dbg.pid}:#{@dbg.tid} #{@dbg.state} #{@dbg.info}"
|
|
537
578
|
draw_string_color(:status, w_w-str.length*@font_width-1, y, str)
|
|
538
579
|
draw_string_color(:status, 1+@font_width, y, @statusline)
|
|
539
|
-
|
|
580
|
+
y -= @font_height
|
|
540
581
|
|
|
541
582
|
w_w_c = w_w/@font_width
|
|
542
583
|
@caret_y = y
|
|
@@ -744,7 +785,7 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
744
785
|
def cmd_dd(addr, dlen=nil, len=nil)
|
|
745
786
|
if addr.kind_of? String
|
|
746
787
|
s = addr.strip
|
|
747
|
-
addr = solve_expr!(s)
|
|
788
|
+
addr = solve_expr!(s) || @parent_widget.mem.curaddr
|
|
748
789
|
if not s.empty?
|
|
749
790
|
s = s[1..-1] if s[0] == ?,
|
|
750
791
|
len ||= solve_expr(s)
|
|
@@ -757,7 +798,7 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
757
798
|
le = (@dbg.cpu.endianness == :little)
|
|
758
799
|
data = '' if @dbg.memory.page_invalid?(addr)
|
|
759
800
|
case dlen
|
|
760
|
-
when nil; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ').ljust(2*16+15)} #{data.tr("
|
|
801
|
+
when nil; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ').ljust(2*16+15)} #{data.tr("^\x20-\x7e", '.')}"
|
|
761
802
|
when 1; add_log "#{Expression[addr]} #{data.unpack('C*').map { |c| '%02X' % c }.join(' ')}"
|
|
762
803
|
when 2; add_log "#{Expression[addr]} #{data.unpack(le ? 'v*' : 'n*').map { |c| '%04X' % c }.join(' ')}"
|
|
763
804
|
when 4; add_log "#{Expression[addr]} #{data.unpack(le ? 'V*' : 'N*').map { |c| '%08X' % c }.join(' ')}"
|
|
@@ -767,8 +808,12 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
767
808
|
len -= 16
|
|
768
809
|
end
|
|
769
810
|
else
|
|
770
|
-
|
|
771
|
-
|
|
811
|
+
if dlen
|
|
812
|
+
@parent_widget.mem.view(:hex).data_size = dlen
|
|
813
|
+
@parent_widget.mem.view(:hex).resized
|
|
814
|
+
@parent_widget.mem.showview(:hex)
|
|
815
|
+
end
|
|
816
|
+
@parent_widget.mem.focus_addr(solve_expr(addr))
|
|
772
817
|
@parent_widget.mem.gui_update
|
|
773
818
|
end
|
|
774
819
|
end
|
|
@@ -783,6 +828,18 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
783
828
|
new_command('dw', 'dump/focus words in data window') { |arg| cmd_dd(arg, 2) }
|
|
784
829
|
new_command('dd', 'dump/focus dwords in data window') { |arg| cmd_dd(arg, 4) }
|
|
785
830
|
new_command('dq', 'dump/focus qwords in data window') { |arg| cmd_dd(arg, 8) }
|
|
831
|
+
new_command('dc', 'focus C struct in data window: <name> <addr>') { |arg|
|
|
832
|
+
name, addr = arg.strip.split(/\s+/, 2)
|
|
833
|
+
addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
|
|
834
|
+
@parent_widget.mem.focus_addr(addr, :cstruct, false, name)
|
|
835
|
+
}
|
|
836
|
+
new_command('dC', 'dump C struct: dC <name> <addr>') { |arg|
|
|
837
|
+
name, addr = arg.strip.split(/\s+/, 2)
|
|
838
|
+
addr = (addr ? solve_expr(addr) : @parent_widget.mem.curaddr)
|
|
839
|
+
if st = @dbg.disassembler.c_parser.decode_c_struct(name, @dbg.memory, addr)
|
|
840
|
+
add_log st.to_s.gsub("\t", ' ')
|
|
841
|
+
end
|
|
842
|
+
}
|
|
786
843
|
new_command('u', 'focus code window on an address') { |arg| p.code.focus_addr(solve_expr(arg)) }
|
|
787
844
|
new_command('.', 'focus code window on current address') { p.code.focus_addr(solve_expr(@dbg.register_pc.to_s)) }
|
|
788
845
|
new_command('wc', 'set code window height') { |arg|
|
|
@@ -828,12 +885,14 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
828
885
|
cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
|
|
829
886
|
@dbg.bpx(solve_expr(e), o, cd, &cb)
|
|
830
887
|
}
|
|
831
|
-
new_command('hwbp', 'set a hardware breakpoint') { |arg|
|
|
832
|
-
arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
|
|
833
|
-
e, c, a = $1,
|
|
888
|
+
new_command('hwbp', 'set a hardware breakpoint (hwbp 0x2345 w)') { |arg|
|
|
889
|
+
arg =~ /^(.*?)( once)?( [rwx])?(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
|
|
890
|
+
e, o, t, c, a = $1, $2, $3, ($4 || $6), $5
|
|
891
|
+
o = o ? true : false
|
|
892
|
+
t = (t || 'x').strip.to_sym
|
|
834
893
|
cd = parse_expr(c) if c
|
|
835
894
|
cb = lambda { a.split(';').each { |aaa| run_command(aaa) } } if a
|
|
836
|
-
@dbg.hwbp(solve_expr(e),
|
|
895
|
+
@dbg.hwbp(solve_expr(e), t, 1, o, cd, &cb)
|
|
837
896
|
}
|
|
838
897
|
new_command('bpm', 'set a hardware memory breakpoint: bpm r 0x4800ff 16') { |arg|
|
|
839
898
|
arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
|
|
@@ -846,7 +905,7 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
846
905
|
exp = solve_expr!(e)
|
|
847
906
|
len = solve_expr(e) if e != ''
|
|
848
907
|
len ||= 1
|
|
849
|
-
@dbg.
|
|
908
|
+
@dbg.bpm(exp, mode, len, false, cd, &cb)
|
|
850
909
|
}
|
|
851
910
|
new_command('g', 'wait until target reaches the specified address') { |arg|
|
|
852
911
|
arg =~ /^(.*?)(?: if (.*?))?(?: do (.*?))?(?: if (.*?))?$/i
|
|
@@ -1038,7 +1097,7 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
1038
1097
|
add_log "#{t} #{stf[:state]} #{stf[:info]}"
|
|
1039
1098
|
}
|
|
1040
1099
|
}
|
|
1041
|
-
|
|
1100
|
+
|
|
1042
1101
|
new_command('pid', 'select a pid') { |arg|
|
|
1043
1102
|
if pid = solve_expr(arg)
|
|
1044
1103
|
@dbg.pid = pid
|
|
@@ -1072,7 +1131,7 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
1072
1131
|
@dbg.ignore_newthread = false
|
|
1073
1132
|
@dbg.ignore_endthread = false
|
|
1074
1133
|
}
|
|
1075
|
-
new_command('
|
|
1134
|
+
new_command('thread_events_ignore', 'ignore thread creation/termination') {
|
|
1076
1135
|
@dbg.ignore_newthread = true
|
|
1077
1136
|
@dbg.ignore_endthread = true
|
|
1078
1137
|
}
|
|
@@ -1101,6 +1160,12 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
1101
1160
|
@dbg.create_process(arg)
|
|
1102
1161
|
}
|
|
1103
1162
|
|
|
1163
|
+
new_command('plugin', 'load', 'load a debugger plugin') { |arg|
|
|
1164
|
+
@dbg.load_plugin arg
|
|
1165
|
+
add_log "loaded plugin #{File.basename(arg, '.rb')}"
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
|
|
1104
1169
|
@dbg.ui_command_setup(self) if @dbg.respond_to? :ui_command_setup
|
|
1105
1170
|
end
|
|
1106
1171
|
|
|
@@ -1122,12 +1187,13 @@ class DbgConsoleWidget < DrawableWidget
|
|
|
1122
1187
|
end
|
|
1123
1188
|
|
|
1124
1189
|
def run_command(cmd)
|
|
1190
|
+
cmd = cmd.sub(/^\s+/, '')
|
|
1125
1191
|
cn = cmd.split.first
|
|
1126
1192
|
if not @commands[cn]
|
|
1127
1193
|
a = @commands.keys.find_all { |k| k[0, cn.length] == cn }
|
|
1128
1194
|
cn = a.first if a.length == 1
|
|
1129
1195
|
end
|
|
1130
|
-
if pc = @commands[cn]
|
|
1196
|
+
if pc = @commands[cn]
|
|
1131
1197
|
pc[cmd.split(/\s+/, 2)[1].to_s]
|
|
1132
1198
|
else
|
|
1133
1199
|
add_log 'unknown command'
|
|
@@ -145,7 +145,7 @@ end
|
|
|
145
145
|
class DrawableWidget < Gtk::DrawingArea
|
|
146
146
|
include Msgbox
|
|
147
147
|
|
|
148
|
-
attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word
|
|
148
|
+
attr_accessor :parent_widget, :caret_x, :caret_y, :hl_word, :hl_word_re
|
|
149
149
|
# this hash is used to determine the colors of the Gui elements (background, caret, ...)
|
|
150
150
|
# modifications to it are only useful before the widget is first rendered (IE before Gui.main)
|
|
151
151
|
attr_accessor :default_color_association
|
|
@@ -153,7 +153,7 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
153
153
|
# keypress event keyval traduction table
|
|
154
154
|
Keyboard_trad = Gdk::Keyval.constants.grep(/^GDK_/).inject({}) { |h, cst|
|
|
155
155
|
v = Gdk::Keyval.const_get(cst)
|
|
156
|
-
key = cst.to_s.sub(/^GDK_/, '').sub(/^KP_/, '')
|
|
156
|
+
key = cst.to_s.sub(/^GDK_/, '').sub(/^KEY_/, '').sub(/^KP_/, '')
|
|
157
157
|
if key.length == 1
|
|
158
158
|
key = key[0] # ?a, ?b etc
|
|
159
159
|
else
|
|
@@ -161,7 +161,7 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
161
161
|
key = {
|
|
162
162
|
:page_up => :pgup, :page_down => :pgdown, :next => :pgdown,
|
|
163
163
|
:escape => :esc, :return => :enter, :l1 => :f11, :l2 => :f12,
|
|
164
|
-
:prior => :pgup,
|
|
164
|
+
:prior => :pgup, :menu => :popupmenu,
|
|
165
165
|
|
|
166
166
|
:space => ?\ ,
|
|
167
167
|
:asciitilde => ?~, :quoteleft => ?`,
|
|
@@ -189,6 +189,15 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
189
189
|
h.update v => key
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
BasicColor = { :white => 'fff', :palegrey => 'ddd', :black => '000', :grey => '444',
|
|
193
|
+
:red => 'f44', :darkred => '800', :palered => 'faa',
|
|
194
|
+
:green => '4f4', :darkgreen => '080', :palegreen => 'afa',
|
|
195
|
+
:blue => '44f', :darkblue => '008', :paleblue => 'aaf',
|
|
196
|
+
:yellow => 'ff4', :darkyellow => '440', :paleyellow => 'ffa',
|
|
197
|
+
:orange => 'fc8',
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
192
201
|
def initialize(*a, &b)
|
|
193
202
|
@parent_widget = nil
|
|
194
203
|
|
|
@@ -226,7 +235,6 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
226
235
|
grab_focus
|
|
227
236
|
case ev.button
|
|
228
237
|
when 1; protect { click(ev.x, ev.y) } if respond_to? :click
|
|
229
|
-
when 3; protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
|
|
230
238
|
end
|
|
231
239
|
when Gdk::Event::Type::BUTTON2_PRESS
|
|
232
240
|
case ev.button
|
|
@@ -245,8 +253,11 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
245
253
|
} if respond_to? :mousemove
|
|
246
254
|
|
|
247
255
|
signal_connect('button_release_event') { |w, ev|
|
|
248
|
-
|
|
249
|
-
|
|
256
|
+
case ev.button
|
|
257
|
+
when 1; protect { mouserelease(ev.x, ev.y) } if respond_to? :mouserelease
|
|
258
|
+
when 3; protect { rightclick(ev.x, ev.y) } if respond_to? :rightclick
|
|
259
|
+
end
|
|
260
|
+
}
|
|
250
261
|
|
|
251
262
|
signal_connect('scroll_event') { |w, ev|
|
|
252
263
|
dir = case ev.direction
|
|
@@ -273,12 +284,7 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
273
284
|
}
|
|
274
285
|
|
|
275
286
|
signal_connect('realize') {
|
|
276
|
-
{
|
|
277
|
-
:red => 'f00', :darkred => '800', :palered => 'fcc',
|
|
278
|
-
:green => '0f0', :darkgreen => '080', :palegreen => 'cfc',
|
|
279
|
-
:blue => '00f', :darkblue => '008', :paleblue => 'ccf',
|
|
280
|
-
:yellow => 'ff0', :darkyellow => '440', :paleyellow => 'ffc',
|
|
281
|
-
}.each { |tag, val|
|
|
287
|
+
BasicColor.each { |tag, val|
|
|
282
288
|
@color[tag] = color(val)
|
|
283
289
|
}
|
|
284
290
|
|
|
@@ -302,7 +308,11 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
302
308
|
# create a color from a 'rgb' description
|
|
303
309
|
def color(val)
|
|
304
310
|
if not @color[val]
|
|
305
|
-
|
|
311
|
+
v = case val.length
|
|
312
|
+
when 3; val.scan(/./).map { |c| (c*4).to_i(16) }
|
|
313
|
+
when 6; val.scan(/../).map { |c| (c+c).to_i(16) }
|
|
314
|
+
end
|
|
315
|
+
@color[val] = Gdk::Color.new(*v)
|
|
306
316
|
window.colormap.alloc_color(@color[val], true, true)
|
|
307
317
|
end
|
|
308
318
|
@color[val]
|
|
@@ -325,20 +335,48 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
325
335
|
|
|
326
336
|
# change the color association
|
|
327
337
|
# arg is a hash function symbol => color symbol
|
|
328
|
-
# color must be allocated
|
|
329
338
|
# check #initialize/sig('realize') for initial function/color list
|
|
339
|
+
# if called before the widget is first displayed onscreen, will register a hook to re-call itself later
|
|
330
340
|
def set_color_association(hash)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
341
|
+
if not realized?
|
|
342
|
+
sid = signal_connect('realize') {
|
|
343
|
+
signal_handler_disconnect(sid)
|
|
344
|
+
set_color_association(hash)
|
|
345
|
+
}
|
|
346
|
+
else
|
|
347
|
+
hord = Hash.new { |h, k| h[k] = (hash[k] ? h[hash[k]] + 1 : 0) }
|
|
348
|
+
hash.sort_by { |k, v| hord[k] }.each { |k, v| @color[k] = color(v) }
|
|
349
|
+
modify_bg Gtk::STATE_NORMAL, @color[:background]
|
|
350
|
+
gui_update
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def new_menu
|
|
355
|
+
toplevel.new_menu
|
|
356
|
+
end
|
|
357
|
+
def addsubmenu(*a, &b)
|
|
358
|
+
toplevel.addsubmenu(*a, &b)
|
|
359
|
+
end
|
|
360
|
+
def popupmenu(m, x, y)
|
|
361
|
+
toplevel.popupmenu(m, (x+allocation.x).to_i, (y+allocation.y).to_i)
|
|
334
362
|
end
|
|
335
363
|
|
|
336
364
|
# update @hl_word from a line & offset, return nil if unchanged
|
|
337
|
-
def update_hl_word(line, offset)
|
|
365
|
+
def update_hl_word(line, offset, mode=:asm)
|
|
338
366
|
return if not line
|
|
339
367
|
word = line[0...offset].to_s[/\w*$/] << line[offset..-1].to_s[/^\w*/]
|
|
340
368
|
word = nil if word == ''
|
|
341
|
-
|
|
369
|
+
if @hl_word != word
|
|
370
|
+
if word
|
|
371
|
+
if mode == :asm and defined?(@dasm) and @dasm
|
|
372
|
+
re = @dasm.gui_hilight_word_regexp(word)
|
|
373
|
+
else
|
|
374
|
+
re = Regexp.escape word
|
|
375
|
+
end
|
|
376
|
+
@hl_word_re = /^(.*?)(\b(?:#{re})\b)/
|
|
377
|
+
end
|
|
378
|
+
@hl_word = word
|
|
379
|
+
end
|
|
342
380
|
end
|
|
343
381
|
|
|
344
382
|
def paint
|
|
@@ -385,6 +423,20 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
385
423
|
end
|
|
386
424
|
|
|
387
425
|
def draw_rectangle(x, y, w, h)
|
|
426
|
+
# GTK clips coords around 0x8000
|
|
427
|
+
return if x > 0x7000 or y > 0x7000
|
|
428
|
+
if x < -0x7000
|
|
429
|
+
w += x + 100
|
|
430
|
+
x = -100
|
|
431
|
+
end
|
|
432
|
+
if y < -0x7000
|
|
433
|
+
h += y + 100
|
|
434
|
+
y = -100
|
|
435
|
+
end
|
|
436
|
+
return if w <= 0 or h <= 0
|
|
437
|
+
w = 0x7000 if w > 0x7000
|
|
438
|
+
h = 0x7000 if h > 0x7000
|
|
439
|
+
|
|
388
440
|
@w.draw_rectangle(@gc, true, x, y, w, h)
|
|
389
441
|
end
|
|
390
442
|
|
|
@@ -394,6 +446,29 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
394
446
|
end
|
|
395
447
|
|
|
396
448
|
def draw_line(x, y, ex, ey)
|
|
449
|
+
if x.abs > 0x7000
|
|
450
|
+
return if ex.abs > 0x7000 and ((ex < 0) == (x < 0))
|
|
451
|
+
ox = x
|
|
452
|
+
x = ((x > 0) ? 0x7000 : -0x7000)
|
|
453
|
+
y = ey+(x-ex)*(y-ey)/(ox-ex)
|
|
454
|
+
end
|
|
455
|
+
if ex.abs > 0x7000
|
|
456
|
+
oex = ex
|
|
457
|
+
ex = ((ex > 0) ? 0x7000 : -0x7000)
|
|
458
|
+
ey = y+(ex-x)*(ey-y)/(oex-x)
|
|
459
|
+
end
|
|
460
|
+
if y.abs > 0x7000
|
|
461
|
+
return if ey.abs > 0x7000 and ((ey < 0) == (y < 0))
|
|
462
|
+
oy = y
|
|
463
|
+
y = ((y > 0) ? 0x7000 : -0x7000)
|
|
464
|
+
x = ex+(y-ey)*(x-ex)/(oy-ey)
|
|
465
|
+
end
|
|
466
|
+
if ey.abs > 0x7000
|
|
467
|
+
oey = ey
|
|
468
|
+
ey = ((ey > 0) ? 0x7000 : -0x7000)
|
|
469
|
+
ex = x+(ey-y)*(ex-x)/(oey-y)
|
|
470
|
+
end
|
|
471
|
+
|
|
397
472
|
@w.draw_line(@gc, x, y, ex, ey)
|
|
398
473
|
end
|
|
399
474
|
|
|
@@ -403,6 +478,7 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
403
478
|
end
|
|
404
479
|
|
|
405
480
|
def draw_string(x, y, str)
|
|
481
|
+
return if x.abs > 0x7000 or y.abs > 0x7000
|
|
406
482
|
@layout.text = str
|
|
407
483
|
@w.draw_layout(@gc, x, y, @layout)
|
|
408
484
|
end
|
|
@@ -412,6 +488,23 @@ class DrawableWidget < Gtk::DrawingArea
|
|
|
412
488
|
draw_string(x, y, str)
|
|
413
489
|
end
|
|
414
490
|
|
|
491
|
+
# same as draw_string_color + hilight @hl_word_re
|
|
492
|
+
def draw_string_hl(col, x, y, str)
|
|
493
|
+
if @hl_word
|
|
494
|
+
while str =~ @hl_word_re
|
|
495
|
+
s1, s2 = $1, $2
|
|
496
|
+
draw_string_color(col, x, y, s1)
|
|
497
|
+
x += s1.length*@font_width
|
|
498
|
+
hl_w = s2.length*@font_width
|
|
499
|
+
draw_rectangle_color(:hl_word_bg, x, y, hl_w, @font_height)
|
|
500
|
+
draw_string_color(:hl_word, x, y, s2)
|
|
501
|
+
x += hl_w
|
|
502
|
+
str = str[s1.length+s2.length..-1]
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
draw_string_color(col, x, y, str)
|
|
506
|
+
end
|
|
507
|
+
|
|
415
508
|
def clipboard_copy(buf)
|
|
416
509
|
clipboard = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
|
|
417
510
|
clipboard.text = buf
|
|
@@ -477,15 +570,35 @@ class InputBox < Gtk::Dialog
|
|
|
477
570
|
@textwidget = Gtk::TextView.new
|
|
478
571
|
if opts[:text]
|
|
479
572
|
@textwidget.buffer.text = opts[:text].to_s
|
|
480
|
-
|
|
481
|
-
@textwidget.buffer.move_mark('insert', @textwidget.buffer.end_iter)
|
|
573
|
+
text_select_all
|
|
482
574
|
end
|
|
483
575
|
|
|
576
|
+
@@history ||= {}
|
|
577
|
+
histkey = opts[:history] || str[0, 10]
|
|
578
|
+
@history = (@@history[histkey] ||= [])
|
|
579
|
+
@history_off = @history.length
|
|
580
|
+
|
|
484
581
|
@textwidget.signal_connect('key_press_event') { |w, ev|
|
|
485
582
|
key = DrawableWidget::Keyboard_trad[ev.keyval]
|
|
486
583
|
case key
|
|
487
|
-
when :escape
|
|
488
|
-
|
|
584
|
+
when :escape
|
|
585
|
+
response(RESPONSE_REJECT)
|
|
586
|
+
true
|
|
587
|
+
when :enter
|
|
588
|
+
@history << @textwidget.buffer.text.to_s
|
|
589
|
+
@history.pop if @history.last == ''
|
|
590
|
+
@history.pop if @history.last == @history[-2]
|
|
591
|
+
response(RESPONSE_ACCEPT)
|
|
592
|
+
true
|
|
593
|
+
when :up, :down
|
|
594
|
+
txt = @textwidget.buffer.text.to_s
|
|
595
|
+
if (@history_off < @history.length or @history.last != txt)
|
|
596
|
+
@history[@history_off] = txt
|
|
597
|
+
end
|
|
598
|
+
@history_off += (key == :up ? -1 : 1)
|
|
599
|
+
@history_off %= @history.length
|
|
600
|
+
@textwidget.buffer.text = @history[@history_off].to_s
|
|
601
|
+
text_select_all
|
|
489
602
|
end
|
|
490
603
|
}
|
|
491
604
|
|
|
@@ -502,9 +615,9 @@ class InputBox < Gtk::Dialog
|
|
|
502
615
|
Gtk::Drag.dest_set(self,
|
|
503
616
|
Gtk::Drag::DEST_DEFAULT_MOTION |
|
|
504
617
|
Gtk::Drag::DEST_DEFAULT_DROP,
|
|
505
|
-
|
|
618
|
+
[['text/plain', 0, 0], ['text/uri-list', 0, 0]],
|
|
506
619
|
Gdk::DragContext::ACTION_COPY | Gdk::DragContext::ACTION_MOVE)
|
|
507
|
-
|
|
620
|
+
|
|
508
621
|
signal_connect('drag_data_received') { |w, dc, x, y, data, info, time|
|
|
509
622
|
dc.targets.each { |target|
|
|
510
623
|
next if target.name != 'text/plain' and target.name != 'text/uri-list'
|
|
@@ -521,6 +634,11 @@ class InputBox < Gtk::Dialog
|
|
|
521
634
|
present
|
|
522
635
|
end
|
|
523
636
|
|
|
637
|
+
def text_select_all
|
|
638
|
+
@textwidget.buffer.move_mark('selection_bound', @textwidget.buffer.start_iter)
|
|
639
|
+
@textwidget.buffer.move_mark('insert', @textwidget.buffer.end_iter)
|
|
640
|
+
end
|
|
641
|
+
|
|
524
642
|
def text ; @textwidget.buffer.text ; end
|
|
525
643
|
def text=(nt) ; @textwidget.buffer.text = nt ; end
|
|
526
644
|
end
|
|
@@ -604,7 +722,7 @@ class ListWindow < Gtk::Dialog
|
|
|
604
722
|
tvc = Gtk::TreeViewColumn.new(col, crt)
|
|
605
723
|
tvc.sort_column_id = i
|
|
606
724
|
tvc.set_cell_data_func(crt) { |_tvc, _crt, model, iter|
|
|
607
|
-
|
|
725
|
+
_crt.text = iter[i]
|
|
608
726
|
if @color_callback
|
|
609
727
|
fu = (0...cols.length).map { |ii| iter[ii] }
|
|
610
728
|
fg, bg = @color_callback[fu]
|
|
@@ -635,7 +753,7 @@ class ListWindow < Gtk::Dialog
|
|
|
635
753
|
|
|
636
754
|
remove vbox
|
|
637
755
|
add Gtk::ScrolledWindow.new.add(treeview)
|
|
638
|
-
toplevel.set_default_size cols.length*
|
|
756
|
+
toplevel.set_default_size cols.length*240, 400
|
|
639
757
|
|
|
640
758
|
show if not h[:noshow]
|
|
641
759
|
|
|
@@ -666,6 +784,7 @@ class Window < Gtk::Window
|
|
|
666
784
|
@menubar = Gtk::MenuBar.new
|
|
667
785
|
@accel_group = Gtk::AccelGroup.new
|
|
668
786
|
|
|
787
|
+
set_gravity Gdk::Window::GRAVITY_STATIC
|
|
669
788
|
@vbox.add @menubar, 'expand' => false
|
|
670
789
|
@child = nil
|
|
671
790
|
s = Gdk::Screen.default
|
|
@@ -678,14 +797,13 @@ class Window < Gtk::Window
|
|
|
678
797
|
initialize_window(*a, &b)
|
|
679
798
|
build_menu
|
|
680
799
|
update_menu
|
|
681
|
-
|
|
682
|
-
|
|
800
|
+
|
|
683
801
|
Gtk::Drag.dest_set(self,
|
|
684
802
|
Gtk::Drag::DEST_DEFAULT_MOTION |
|
|
685
803
|
Gtk::Drag::DEST_DEFAULT_DROP,
|
|
686
|
-
|
|
804
|
+
[['text/plain', 0, 0], ['text/uri-list', 0, 0]],
|
|
687
805
|
Gdk::DragContext::ACTION_COPY | Gdk::DragContext::ACTION_MOVE)
|
|
688
|
-
|
|
806
|
+
|
|
689
807
|
signal_connect('drag_data_received') { |w, dc, x, y, data, info, time|
|
|
690
808
|
dc.targets.each { |target|
|
|
691
809
|
next if target.name != 'text/plain' and target.name != 'text/uri-list'
|
|
@@ -734,6 +852,13 @@ class Window < Gtk::Window
|
|
|
734
852
|
l.grep(::Array).first if l
|
|
735
853
|
end
|
|
736
854
|
|
|
855
|
+
def popupmenu(m, x, y)
|
|
856
|
+
mh = Gtk::Menu.new
|
|
857
|
+
m.each { |e| create_menu_item(mh, e) }
|
|
858
|
+
mh.show_all
|
|
859
|
+
mh.popup(nil, nil, 2, 0) { |_m, _x, _y, _p| [position[0]+x, position[1]+y, true] }
|
|
860
|
+
end
|
|
861
|
+
|
|
737
862
|
# append stuff to a menu
|
|
738
863
|
# arglist:
|
|
739
864
|
# empty = menu separator
|
|
@@ -801,13 +926,10 @@ class Window < Gtk::Window
|
|
|
801
926
|
key = accel[-1]
|
|
802
927
|
if key == ?>
|
|
803
928
|
key = accel[/<(.*)>/, 1]
|
|
804
|
-
key = case key
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
when /^f(\d\d?)$/i; Gdk::Keyval.const_get("GDK_#{key.upcase}")
|
|
809
|
-
else ??
|
|
810
|
-
end
|
|
929
|
+
key = DrawableWidget::Keyboard_trad.index(case key
|
|
930
|
+
when 'enter', 'esc', 'tab', /^f(\d\d?)$/i; key.downcase.to_sym
|
|
931
|
+
else ??
|
|
932
|
+
end)
|
|
811
933
|
end
|
|
812
934
|
key = key.unpack('C')[0] if key.kind_of? String # yay rb19
|
|
813
935
|
item.add_accelerator('activate', @accel_group, key, (accel[0] == ?^ ? Gdk::Window::CONTROL_MASK : 0), Gtk::ACCEL_VISIBLE)
|
|
@@ -815,7 +937,7 @@ class Window < Gtk::Window
|
|
|
815
937
|
if action
|
|
816
938
|
a = action
|
|
817
939
|
if check
|
|
818
|
-
a = lambda {
|
|
940
|
+
a = lambda { |it| it.active = action.call(it.active?) }
|
|
819
941
|
end
|
|
820
942
|
item.signal_connect('activate') { protect { a.call(item) } }
|
|
821
943
|
end
|
|
@@ -838,7 +960,7 @@ class ToolWindow < Gtk::Dialog
|
|
|
838
960
|
initialize_window(*a, &b)
|
|
839
961
|
show_all
|
|
840
962
|
end
|
|
841
|
-
|
|
963
|
+
|
|
842
964
|
def widget=(w)
|
|
843
965
|
remove @child if @child
|
|
844
966
|
@child = w
|